[upstream] merge with master branch

This commit is contained in:
Philip Müller 2018-10-23 18:53:05 +02:00
commit 0bdc8f11db
54 changed files with 1433 additions and 243 deletions

22
CHANGES
View File

@ -8,14 +8,36 @@ website will have to do for older versions.
This release contains contributions from (alphabetically by first name):
- Alf Gaida
- Caio Carvalho
- Kevin Kofler
- Philip Mueller
- Scott Harvey
## Core ##
* The Calamares application now recognizes the `-X` or `--xdg-config`
option, which adds XDG_DATA_DIRS to the places used to find QML
and branding directories, and XDG_CONFIG_DIRS to the places used
to find the global settings and module configurations. This allows
a more fine-grained, and more layered, approach to setting up
Calamares configurations (in particular, distro's can **add**
configuration files and give them priority, instead of **forking**
configuration files).
## Modules ##
* The *partition* module supports RAID devices, but only when Calamares
is compiled with the newest KPMCore release.
* The calculation of required space -- including swap -- has been simplified,
and Calamares no longer reserves 2GiB of space in calculations for internal
use (this means that it no longer mysteriously drops swap when the disk
size is close to the required installation size).
* The *keyboard* module now handles the (bogus) Austrian keymap for
the system console properly.
* The *preservefiles* module now has a mechanism for setting the permissions
(and ownership) of preserved files.
* New module *fsresizer* can be used to resize filesystems. It is intended
for use in OEM installs where an image of fixed size is created,
and then sized to the actual SD card the user has used.
# 3.2.2 (2018-09-04) #

View File

@ -237,6 +237,11 @@ set_package_properties(
find_package(ECM ${ECM_VERSION} NO_MODULE)
if( ECM_FOUND )
set(CMAKE_MODULE_PATH ${ECM_MODULE_PATH} ${CMAKE_MODULE_PATH})
if ( BUILD_TESTING )
# ECM implies that we can build the tests, too
find_package( Qt5 COMPONENTS Test REQUIRED )
include( ECMAddTests )
endif()
endif()
find_package( KF5 COMPONENTS CoreAddons Crash )

View File

@ -14,165 +14,165 @@ Categories=Qt;System;
X-AppStream-Ignore=true
Name[ar]=نظام التثبيت
Icon[be]=calamares
GenericName[be]=Усталёўшчык сістэмы
Comment[be]=Calamares усталёўшчык сістэмы
Icon[be]=calamares
Name[be]=Усталяваць сістэму
Icon[bg]=calamares
GenericName[bg]=Системен Инсталатор
GenericName[be]=Усталёўшчык сістэмы
Comment[bg]=Calamares Системен Инсталатор
Icon[bg]=calamares
Name[bg]=Инсталирай системата
Icon[ca]=calamares
GenericName[ca]=Instal·lador de sistema
GenericName[bg]=Системен Инсталатор
Comment[ca]=Calamares Instal·lador de sistema
Icon[ca]=calamares
Name[ca]=Instal·la el sistema
Icon[da]=calamares
GenericName[da]=Systeminstallationsprogram
GenericName[ca]=Instal·lador de sistema
Comment[da]=Calamares Systeminstallationsprogram
Icon[da]=calamares
Name[da]=Installér system
Icon[de]=calamares
GenericName[de]=Installation des Betriebssystems
GenericName[da]=Systeminstallationsprogram
Comment[de]=Calamares - Installation des Betriebssystems
Icon[de]=calamares
Name[de]=System installieren
Icon[el]=calamares
GenericName[el]=Εγκατάσταση συστήματος
GenericName[de]=Installation des Betriebssystems
Comment[el]=Calamares Εγκατάσταση συστήματος
Icon[el]=calamares
Name[el]=Εγκατάσταση συστήματος
Icon[en_GB]=calamares
GenericName[en_GB]=System Installer
GenericName[el]=Εγκατάσταση συστήματος
Comment[en_GB]=Calamares System Installer
Icon[en_GB]=calamares
Name[en_GB]=Install System
Icon[es]=calamares
GenericName[es]=Instalador del Sistema
GenericName[en_GB]=System Installer
Comment[es]=Calamares Instalador del Sistema
Icon[es]=calamares
Name[es]=Instalar Sistema
Icon[et]=calamares
GenericName[et]=Süsteemipaigaldaja
GenericName[es]=Instalador del Sistema
Comment[et]=Calamares süsteemipaigaldaja
Icon[et]=calamares
Name[et]=Paigalda süsteem
GenericName[et]=Süsteemipaigaldaja
Name[eu]=Sistema instalatu
Name[es_PR]=Instalar el sistema
Icon[fr]=calamares
GenericName[fr]=Installateur système
Comment[fr]=Calamares - Installateur système
Icon[fr]=calamares
Name[fr]=Installer le système
GenericName[fr]=Installateur système
Name[gl]=Instalación do Sistema
Icon[he]=calamares
GenericName[he]=אשף התקנה
Comment[he]=Calamares - אשף התקנה
Icon[he]=calamares
Name[he]=התקנת מערכת
Icon[hi]=calamares
GenericName[hi]=ि
GenericName[he]=אשף התקנה
Comment[hi]=Calamares ि
Icon[hi]=calamares
Name[hi]=ि
Icon[hr]=calamares
GenericName[hr]=Instalacija sustava
GenericName[hi]=ि
Comment[hr]=Calamares Instalacija sustava
Icon[hr]=calamares
Name[hr]=Instaliraj sustav
Icon[hu]=calamares
GenericName[hu]=Rendszer Telepítő
GenericName[hr]=Instalacija sustava
Comment[hu]=Calamares Rendszer Telepítő
Icon[hu]=calamares
Name[hu]=Rendszer telepítése
Icon[id]=calamares
GenericName[id]=Pemasang
GenericName[hu]=Rendszer Telepítő
Comment[id]=Calamares Pemasang Sistem
Icon[id]=calamares
Name[id]=Instal Sistem
Icon[is]=calamares
GenericName[is]=Kerfis uppsetning
GenericName[id]=Pemasang
Comment[is]=Calamares Kerfis uppsetning
Icon[is]=calamares
Name[is]=Setja upp kerfið
Icon[cs_CZ]=calamares
GenericName[cs_CZ]=Instalátor systému
GenericName[is]=Kerfis uppsetning
Comment[cs_CZ]=Calamares instalátor operačních systémů
Icon[cs_CZ]=calamares
Name[cs_CZ]=Nainstalovat
Icon[ja]=calamares
GenericName[ja]=
GenericName[cs_CZ]=Instalátor systému
Comment[ja]=Calamares
Icon[ja]=calamares
Name[ja]=
Icon[ko]=
GenericName[ko]=
GenericName[ja]=
Comment[ko]=
Icon[ko]=
Name[ko]=
Icon[lt]=calamares
GenericName[lt]=Sistemos diegimas į kompiuterį
GenericName[ko]=
Comment[lt]=Calamares Sistemos diegimo programa
Icon[lt]=calamares
Name[lt]=Įdiegti Sistemą
Icon[it_IT]=calamares
GenericName[it_IT]=Programma d'installazione del sistema
GenericName[lt]=Sistemos diegimas į kompiuterį
Comment[it_IT]=Calamares Programma d'installazione del sistema
Icon[it_IT]=calamares
Name[it_IT]=Installa il sistema
Icon[nb]=calamares
GenericName[nb]=Systeminstallatør
GenericName[it_IT]=Programma d'installazione del sistema
Comment[nb]=Calamares-systeminstallatør
Icon[nb]=calamares
Name[nb]=Installer System
Icon[nl]=calamares
GenericName[nl]=Installatieprogramma
GenericName[nb]=Systeminstallatør
Comment[nl]=Calamares Installatieprogramma
Icon[nl]=calamares
Name[nl]=Installeer systeem
Icon[pl]=calamares
GenericName[pl]=Instalator systemu
GenericName[nl]=Installatieprogramma
Comment[pl]=Calamares Instalator systemu
Icon[pl]=calamares
Name[pl]=Zainstaluj system
Icon[pt_BR]=calamares
GenericName[pt_BR]=Instalador de Sistema
GenericName[pl]=Instalator systemu
Comment[pt_BR]=Calamares Instalador de Sistema
Icon[pt_BR]=calamares
Name[pt_BR]=Sistema de Instalação
Icon[ro]=calamares
GenericName[ro]=Instalator de sistem
GenericName[pt_BR]=Instalador de Sistema
Comment[ro]=Calamares Instalator de sistem
Icon[ro]=calamares
Name[ro]=Instalează sistemul
Icon[ru]=calamares
GenericName[ru]=Установщик системы
GenericName[ro]=Instalator de sistem
Comment[ru]=Calamares - Установщик системы
Icon[ru]=calamares
Name[ru]=Установить систему
Icon[sk]=calamares
GenericName[sk]=Inštalátor systému
GenericName[ru]=Установщик системы
Comment[sk]=Calamares Inštalátor systému
Icon[sk]=calamares
Name[sk]=Inštalovať systém
GenericName[sk]=Inštalátor systému
Name[sl]=Namesti sistem
Icon[sq]=calamares
GenericName[sq]=Instalues Sistemi
Comment[sq]=Calamares Instalues Sistemi
Icon[sq]=calamares
Name[sq]=Instalo Sistemin
Icon[fi_FI]=calamares
GenericName[fi_FI]=Järjestelmän Asennusohjelma
GenericName[sq]=Instalues Sistemi
Comment[fi_FI]=Calamares Järjestelmän Asentaja
Icon[fi_FI]=calamares
Name[fi_FI]=Asenna Järjestelmä
GenericName[fi_FI]=Järjestelmän Asennusohjelma
Name[sr@latin]=Instaliraj sistem
Name[sr]=Инсталирај систем
Icon[sv]=calamares
GenericName[sv]=Systeminstallerare
Comment[sv]=Calamares Systeminstallerare
Icon[sv]=calamares
Name[sv]=Installera system
GenericName[sv]=Systeminstallerare
Name[th]=
GenericName[uk]=Встановлювач системи
Comment[uk]=Calamares - Встановлювач системи
Name[uk]=Встановити Систему
Icon[zh_CN]=calamares
GenericName[zh_CN]=
GenericName[uk]=Встановлювач системи
Comment[zh_CN]=Calamares
Icon[zh_CN]=calamares
Name[zh_CN]=
Icon[zh_TW]=calamares
GenericName[zh_TW]=
GenericName[zh_CN]=
Comment[zh_TW]=Calamares
Icon[zh_TW]=calamares
Name[zh_TW]=
Icon[ast]=calamares
GenericName[ast]=Instalador del sistema
GenericName[zh_TW]=
Comment[ast]=Calamares Instalador del sistema
Icon[ast]=calamares
Name[ast]=Instalar sistema
Icon[eo]=calamares
GenericName[eo]=Sistema Instalilo
GenericName[ast]=Instalador del sistema
Comment[eo]=Calamares Sistema Instalilo
Icon[eo]=calamares
Name[eo]=Instali Sistemo
Icon[es_MX]=calamares
GenericName[es_MX]=Instalador del sistema
GenericName[eo]=Sistema Instalilo
Comment[es_MX]=Calamares - Instalador del sistema
Icon[es_MX]=calamares
Name[es_MX]=Instalar el Sistema
Icon[pt_PT]=calamares
GenericName[pt_PT]=Instalador de Sistema
GenericName[es_MX]=Instalador del sistema
Comment[pt_PT]=Calamares - Instalador de Sistema
Icon[pt_PT]=calamares
Name[pt_PT]=Instalar Sistema
Icon[tr_TR]=calamares
GenericName[tr_TR]=Sistem Yükleyici
GenericName[pt_PT]=Instalador de Sistema
Comment[tr_TR]=Calamares Sistem Yükleyici
Icon[tr_TR]=calamares
Name[tr_TR]=Sistemi Yükle
GenericName[tr_TR]=Sistem Yükleyici

View File

@ -51,4 +51,4 @@ df -h
echo "# Install results"
install_debugging "$DESTDIR"
$result # Result of make install, above
$result || { echo "! Install failed" ; exit 1 ; } # Result of make install, above

View File

@ -1693,7 +1693,7 @@ Installationsprogrammet vil stoppe og alle ændringer vil gå tabt.</translation
<message>
<location filename="../src/modules/partition/gui/PartitionPage.cpp" line="196"/>
<source>The partition table on %1 already has %2 primary partitions, and no more can be added. Please remove one primary partition and add an extended partition, instead.</source>
<translation>Partitionstabellen %1 har allerede %2 primære partitioner, og der kan ikke tilføjes flere. Fjern venligst en primær partition og tilføj i stedet en udviddet partition.</translation>
<translation>Partitionstabellen %1 har allerede %2 primære partitioner, og der kan ikke tilføjes flere. Fjern venligst en primær partition og tilføj i stedet en udvidet partition.</translation>
</message>
</context>
<context>

View File

@ -4,7 +4,7 @@
<message>
<location filename="../src/modules/partition/gui/BootInfoWidget.cpp" line="69"/>
<source>The &lt;strong&gt;boot environment&lt;/strong&gt; of this system.&lt;br&gt;&lt;br&gt;Older x86 systems only support &lt;strong&gt;BIOS&lt;/strong&gt;.&lt;br&gt;Modern systems usually use &lt;strong&gt;EFI&lt;/strong&gt;, but may also show up as BIOS if started in compatibility mode.</source>
<translation>L&apos;&lt;strong&gt;environnement de démarrage&lt;/strong&gt; de ce système.&lt;br&gt;&lt;br&gt;Les anciens systèmes x86 supportent uniquement le &lt;strong&gt;BIOS&lt;/strong&gt;.&lt;br&gt;Les systèmes récents utilisent habituellement &lt;strong&gt;EFI&lt;/strong&gt;, mais peuvent également afficher BIOS s&apos;ils sont démarrés en mode de compatibilité.</translation>
<translation>L&apos;&lt;strong&gt;environnement de démarrage&lt;/strong&gt; de ce système.&lt;br&gt;&lt;br&gt;Les anciens systèmes x86 supportent uniquement &lt;strong&gt;BIOS&lt;/strong&gt;.&lt;br&gt;Les systèmes récents utilisent habituellement &lt;strong&gt;EFI&lt;/strong&gt;, mais peuvent également afficher BIOS s&apos;ils sont démarrés en mode de compatibilité.</translation>
</message>
<message>
<location filename="../src/modules/partition/gui/BootInfoWidget.cpp" line="79"/>

View File

@ -521,7 +521,7 @@ The installer will quit and all changes will be lost.</source>
<message>
<location filename="../src/modules/contextualprocess/ContextualProcessJob.cpp" line="117"/>
<source>Contextual Processes Job</source>
<translation type="unfinished"/>
<translation>משימת תהליכי הקשר</translation>
</message>
</context>
<context>
@ -2358,7 +2358,7 @@ Output:
<message>
<location filename="../src/modules/shellprocess/ShellProcessJob.cpp" line="51"/>
<source>Shell Processes Job</source>
<translation type="unfinished"/>
<translation>משימת תהליכי מעטפת</translation>
</message>
</context>
<context>

View File

@ -207,7 +207,7 @@
<message>
<location filename="../src/libcalamaresui/ViewManager.cpp" line="277"/>
<source>&amp;Install</source>
<translation type="unfinished"/>
<translation>&amp;Telepítés</translation>
</message>
<message>
<location filename="../src/libcalamaresui/ViewManager.cpp" line="325"/>
@ -229,7 +229,7 @@ Minden változtatás elveszik, ha kilépsz a telepítőből.</translation>
<message>
<location filename="../src/libcalamaresui/ViewManager.cpp" line="332"/>
<source>&amp;No</source>
<translation>@Nem</translation>
<translation>&amp;Nem</translation>
</message>
<message>
<location filename="../src/libcalamaresui/ViewManager.cpp" line="163"/>
@ -944,7 +944,7 @@ Telepítés nem folytatható. &lt;a href=&quot;#details&quot;&gt;Részletek...&l
<message>
<location filename="../src/modules/finished/FinishedPage.ui" line="98"/>
<source>&amp;Restart now</source>
<translation>jraindítás most</translation>
<translation>Új&amp;raindítás most</translation>
</message>
<message>
<location filename="../src/modules/finished/FinishedPage.cpp" line="51"/>

View File

@ -244,7 +244,7 @@ Diegimo programa užbaigs darbą ir visi pakeitimai bus prarasti.</translation>
<message>
<location filename="../src/libcalamaresui/ViewManager.cpp" line="238"/>
<source>The %1 installer is about to make changes to your disk in order to install %2.&lt;br/&gt;&lt;strong&gt;You will not be able to undo these changes.&lt;/strong&gt;</source>
<translation>%1 diegimo programa, siekdama įdiegti %2, ketina atlikti pakeitimus diske.&lt;br/&gt;&lt;strong&gt;Š pakeitimų atšaukti nebegalėsite.&lt;/strong&gt;</translation>
<translation>%1 diegimo programa, siekdama įdiegti %2, ketina atlikti pakeitimus diske.&lt;br/&gt;&lt;strong&gt;Š pakeitimų nebegalėsite atšaukti.&lt;/strong&gt;</translation>
</message>
<message>
<location filename="../src/libcalamaresui/ViewManager.cpp" line="243"/>

View File

@ -50,7 +50,7 @@
<message>
<location filename="../src/libcalamaresui/viewpages/BlankViewStep.cpp" line="69"/>
<source>Blank Page</source>
<translation type="unfinished"/>
<translation>Lege pagina</translation>
</message>
</context>
<context>
@ -192,7 +192,7 @@
<message>
<location filename="../src/libcalamaresui/ViewManager.cpp" line="179"/>
<source>Calamares Initialization Failed</source>
<translation type="unfinished"/>
<translation>Calamares Initialisatie mislukt</translation>
</message>
<message>
<location filename="../src/libcalamaresui/ViewManager.cpp" line="180"/>
@ -202,7 +202,7 @@
<message>
<location filename="../src/libcalamaresui/ViewManager.cpp" line="185"/>
<source>&lt;br/&gt;The following modules could not be loaded:</source>
<translation type="unfinished"/>
<translation>&lt;br/&gt;The volgende modules konden niet worden geladen:</translation>
</message>
<message>
<location filename="../src/libcalamaresui/ViewManager.cpp" line="277"/>
@ -1244,7 +1244,7 @@ Het installatieprogramma zal afsluiten en alle wijzigingen zullen verloren gaan.
<message>
<location filename="../src/modules/users/CheckPWQuality.cpp" line="151"/>
<source>Password is too weak</source>
<translation type="unfinished"/>
<translation>Wachtwoord is te zwak</translation>
</message>
<message>
<location filename="../src/modules/users/CheckPWQuality.cpp" line="158"/>
@ -1259,12 +1259,12 @@ Het installatieprogramma zal afsluiten en alle wijzigingen zullen verloren gaan.
<message>
<location filename="../src/modules/users/CheckPWQuality.cpp" line="164"/>
<source>The password is the same as the old one</source>
<translation type="unfinished"/>
<translation>Het wachtwoord is hetzelfde als het oude wachtwoord</translation>
</message>
<message>
<location filename="../src/modules/users/CheckPWQuality.cpp" line="166"/>
<source>The password is a palindrome</source>
<translation type="unfinished"/>
<translation>Het wachtwoord is een palindroom</translation>
</message>
<message>
<location filename="../src/modules/users/CheckPWQuality.cpp" line="168"/>
@ -1274,12 +1274,12 @@ Het installatieprogramma zal afsluiten en alle wijzigingen zullen verloren gaan.
<message>
<location filename="../src/modules/users/CheckPWQuality.cpp" line="170"/>
<source>The password is too similar to the old one</source>
<translation type="unfinished"/>
<translation>Het wachtwoord lijkt te veel op het oude wachtwoord</translation>
</message>
<message>
<location filename="../src/modules/users/CheckPWQuality.cpp" line="172"/>
<source>The password contains the user name in some form</source>
<translation type="unfinished"/>
<translation>Het wachtwoord bevat de gebruikersnaam op een of andere manier</translation>
</message>
<message>
<location filename="../src/modules/users/CheckPWQuality.cpp" line="174"/>

View File

@ -9,7 +9,7 @@
<message>
<location filename="../src/modules/partition/gui/BootInfoWidget.cpp" line="79"/>
<source>This system was started with an &lt;strong&gt;EFI&lt;/strong&gt; boot environment.&lt;br&gt;&lt;br&gt;To configure startup from an EFI environment, this installer must deploy a boot loader application, like &lt;strong&gt;GRUB&lt;/strong&gt; or &lt;strong&gt;systemd-boot&lt;/strong&gt; on an &lt;strong&gt;EFI System Partition&lt;/strong&gt;. This is automatic, unless you choose manual partitioning, in which case you must choose it or create it on your own.</source>
<translation>&lt;strong&gt;EFI&lt;/strong&gt; &lt;br&gt;&lt;br&gt;使 EFI使 GPT &lt;br&gt; EFI &lt;strong&gt;GRUB&lt;/strong&gt; &lt;strong&gt;systemd-boot&lt;/strong&gt; &lt;strong&gt;EFI &lt;/strong&gt;</translation>
<translation>&lt;strong&gt;EFI&lt;/strong&gt; &lt;br&gt;&lt;br&gt;使 EFI使 GPT &lt;br&gt; EFI &lt;strong&gt;GRUB&lt;/strong&gt; &lt;strong&gt;systemd-boot&lt;/strong&gt; &lt;strong&gt;EFI &lt;/strong&gt;EFIEFI</translation>
</message>
<message>
<location filename="../src/modules/partition/gui/BootInfoWidget.cpp" line="91"/>
@ -51,7 +51,7 @@
<message>
<location filename="../src/libcalamaresui/viewpages/BlankViewStep.cpp" line="69"/>
<source>Blank Page</source>
<translation type="unfinished"/>
<translation></translation>
</message>
</context>
<context>
@ -193,17 +193,17 @@
<message>
<location filename="../src/libcalamaresui/ViewManager.cpp" line="179"/>
<source>Calamares Initialization Failed</source>
<translation type="unfinished"/>
<translation>Calamares安装失败</translation>
</message>
<message>
<location filename="../src/libcalamaresui/ViewManager.cpp" line="180"/>
<source>%1 can not be installed. Calamares was unable to load all of the configured modules. This is a problem with the way Calamares is being used by the distribution.</source>
<translation type="unfinished"/>
<translation>1 Calamares无法加载所有已配置的模块使Calamares的方式的问题</translation>
</message>
<message>
<location filename="../src/libcalamaresui/ViewManager.cpp" line="185"/>
<source>&lt;br/&gt;The following modules could not be loaded:</source>
<translation type="unfinished"/>
<translation>&lt;br/&gt;</translation>
</message>
<message>
<location filename="../src/libcalamaresui/ViewManager.cpp" line="277"/>
@ -265,7 +265,7 @@ The installer will quit and all changes will be lost.</source>
<message>
<location filename="../src/libcalamaresui/ViewManager.cpp" line="284"/>
<source>The installation is complete. Close the installer.</source>
<translation></translation>
<translation></translation>
</message>
<message>
<location filename="../src/libcalamaresui/ViewManager.cpp" line="160"/>
@ -334,7 +334,7 @@ The installer will quit and all changes will be lost.</source>
<message>
<location filename="../src/modules/welcome/checker/CheckerWidget.cpp" line="174"/>
<source>For best results, please ensure that this computer:</source>
<translation>: </translation>
<translation>: </translation>
</message>
<message>
<location filename="../src/modules/welcome/checker/CheckerWidget.cpp" line="202"/>
@ -509,12 +509,12 @@ The installer will quit and all changes will be lost.</source>
<message>
<location filename="../src/libcalamares/utils/CommandList.cpp" line="128"/>
<source>The command runs in the host environment and needs to know the root path, but no rootMountPoint is defined.</source>
<translation type="unfinished"/>
<translation>root挂载点</translation>
</message>
<message>
<location filename="../src/libcalamares/utils/CommandList.cpp" line="139"/>
<source>The command needs to know the user&apos;s name, but no username is defined.</source>
<translation type="unfinished"/>
<translation></translation>
</message>
</context>
<context>
@ -1665,7 +1665,7 @@ The installer will quit and all changes will be lost.</source>
<message>
<location filename="../src/modules/partition/gui/PartitionPage.ui" line="107"/>
<source>Cre&amp;ate</source>
<translation type="unfinished"/>
<translation></translation>
</message>
<message>
<location filename="../src/modules/partition/gui/PartitionPage.ui" line="114"/>
@ -1690,12 +1690,12 @@ The installer will quit and all changes will be lost.</source>
<message>
<location filename="../src/modules/partition/gui/PartitionPage.cpp" line="195"/>
<source>Can not create new partition</source>
<translation type="unfinished"/>
<translation></translation>
</message>
<message>
<location filename="../src/modules/partition/gui/PartitionPage.cpp" line="196"/>
<source>The partition table on %1 already has %2 primary partitions, and no more can be added. Please remove one primary partition and add an extended partition, instead.</source>
<translation type="unfinished"/>
<translation>12</translation>
</message>
</context>
<context>
@ -1841,17 +1841,17 @@ The installer will quit and all changes will be lost.</source>
<message>
<location filename="../src/modules/preservefiles/PreserveFiles.cpp" line="83"/>
<source>Saving files for later ...</source>
<translation type="unfinished"/>
<translation>使</translation>
</message>
<message>
<location filename="../src/modules/preservefiles/PreserveFiles.cpp" line="89"/>
<source>No files configured to save for later.</source>
<translation type="unfinished"/>
<translation>使</translation>
</message>
<message>
<location filename="../src/modules/preservefiles/PreserveFiles.cpp" line="145"/>
<source>Not all of the configured files could be preserved.</source>
<translation type="unfinished"/>
<translation></translation>
</message>
</context>
<context>

Binary file not shown.

View File

@ -10,7 +10,7 @@ msgstr ""
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2018-06-18 07:46-0400\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: miku84, 2017\n"
"Last-Translator: Adriaan de Groot <groot@kde.org>, 2018\n"
"Language-Team: Hungarian (https://www.transifex.com/calamares/teams/20061/hu/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
@ -20,7 +20,7 @@ msgstr ""
#: src/modules/umount/main.py:40
msgid "Unmount file systems."
msgstr ""
msgstr "Fájlrendszerek leválasztása."
#: src/modules/dummypython/main.py:44
msgid "Dummy python job."
@ -47,12 +47,12 @@ msgstr "Csomagok telepítése."
#, python-format
msgid "Installing one package."
msgid_plural "Installing %(num)d packages."
msgstr[0] ""
msgstr[1] ""
msgstr[0] "Egy csomag telepítése."
msgstr[1] "%(num)d csomag telepítése."
#: src/modules/packages/main.py:70
#, python-format
msgid "Removing one package."
msgid_plural "Removing %(num)d packages."
msgstr[0] ""
msgstr[1] ""
msgstr[0] "Egy csomag eltávolítása."
msgstr[1] "%(num)d csomag eltávolítása."

View File

@ -145,6 +145,9 @@ qmlDirCandidates( bool assumeBuilddir )
{
if ( assumeBuilddir )
qmlDirs << QDir::current().absoluteFilePath( "src/qml" ); // In build-dir
if ( CalamaresUtils::haveExtraDirs() )
for ( auto s : CalamaresUtils::extraDataDirs() )
qmlDirs << ( s + QML );
qmlDirs << CalamaresUtils::appDataDir().absoluteFilePath( QML );
}
@ -164,6 +167,9 @@ settingsFileCandidates( bool assumeBuilddir )
{
if ( assumeBuilddir )
settingsPaths << QDir::current().absoluteFilePath( settings );
if ( CalamaresUtils::haveExtraDirs() )
for ( auto s : CalamaresUtils::extraConfigDirs() )
settingsPaths << ( s + settings );
settingsPaths << CMAKE_INSTALL_FULL_SYSCONFDIR "/calamares/settings.conf"; // String concat
settingsPaths << CalamaresUtils::appDataDir().absoluteFilePath( settings );
}
@ -182,6 +188,9 @@ brandingFileCandidates( bool assumeBuilddir, const QString& brandingFilename )
{
if ( assumeBuilddir )
brandingPaths << ( QDir::currentPath() + QStringLiteral( "/src/" ) + brandingFilename );
if ( CalamaresUtils::haveExtraDirs() )
for ( auto s : CalamaresUtils::extraDataDirs() )
brandingPaths << ( s + brandingFilename );
brandingPaths << QDir( CMAKE_INSTALL_FULL_SYSCONFDIR "/calamares/" ).absoluteFilePath( brandingFilename );
brandingPaths << CalamaresUtils::appDataDir().absoluteFilePath( brandingFilename);
}

View File

@ -44,6 +44,8 @@ handle_args( CalamaresApplication& a )
"Verbose output for debugging purposes (0-8).", "level" );
QCommandLineOption configOption( QStringList{ "c", "config"},
"Configuration directory to use, for testing purposes.", "config" );
QCommandLineOption xdgOption( QStringList{"X", "xdg-config"},
"Use XDG_{CONFIG,DATA}_DIRS as well." );
QCommandLineParser parser;
parser.setApplicationDescription( "Distribution-independent installer framework" );
@ -53,6 +55,7 @@ handle_args( CalamaresApplication& a )
parser.addOption( debugOption );
parser.addOption( debugLevelOption );
parser.addOption( configOption );
parser.addOption( xdgOption );
parser.process( a );
@ -72,6 +75,8 @@ handle_args( CalamaresApplication& a )
}
if ( parser.isSet( configOption ) )
CalamaresUtils::setAppDataDir( QDir( parser.value( configOption ) ) );
if ( parser.isSet( xdgOption ) )
CalamaresUtils::setXdgDirs();
}
int

View File

@ -59,6 +59,7 @@ handle_args( QCoreApplication& a )
parser.addOption( debugLevelOption );
parser.addPositionalArgument( "module", "Path or name of module to run." );
parser.addPositionalArgument( "config", "Path of job-config file to use.", "[config]");
parser.process( a );
@ -140,6 +141,8 @@ load_module( const ModuleConfig& moduleConfig )
? moduleDirectory + '/' + name + ".conf"
: moduleConfig.configFile() );
cDebug() << "Module" << moduleName << "job-configuration:" << configFile;
Calamares::Module* module = Calamares::Module::fromDescriptor(
descriptor, name, configFile, moduleDirectory );
@ -158,7 +161,7 @@ main( int argc, char* argv[] )
std::unique_ptr< Calamares::Settings > settings_p( new Calamares::Settings( QString(), true ) );
std::unique_ptr< Calamares::JobQueue > jobqueue_p( new Calamares::JobQueue( nullptr ) );
cDebug() << "Calamares test module-loader" << module.moduleName();
cDebug() << "Calamares module-loader testing" << module.moduleName();
Calamares::Module* m = load_module( module );
if ( !m )
{
@ -175,16 +178,27 @@ main( int argc, char* argv[] )
return 1;
}
cDebug() << "Module" << m->name() << m->typeString() << m->interfaceString();
using TR = Logger::DebugRow<const char*, const QString&>;
cDebug() << "Module metadata"
<< TR( "name", m->name() )
<< TR( "type", m->typeString() )
<< TR( "interface", m->interfaceString() );
cDebug() << "Job outputs:";
Calamares::JobList jobList = m->jobs();
unsigned int count = 1;
for ( const auto& p : jobList )
{
cDebug() << count << p->prettyName();
cDebug() << "Job #" << count << "name" << p->prettyName();
Calamares::JobResult r = p->exec();
if ( !r )
cDebug() << count << ".. failed" << r;
{
using TR = Logger::DebugRow<QString, QString>;
cDebug() << count << ".. failed"
<< TR( "summary", r.message() )
<< TR( "details", r.details() );
}
++count;
}

View File

@ -105,6 +105,19 @@ install( TARGETS calamares
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
)
if ( ECM_FOUND AND BUILD_TESTING )
ecm_add_test(
Tests.cpp
TEST_NAME
libcalamarestest
LINK_LIBRARIES
calamares
Qt5::Core
Qt5::Test
)
set_target_properties( libcalamarestest PROPERTIES AUTOMOC TRUE )
endif()
# Make symlink lib/calamares/libcalamares.so to lib/libcalamares.so.VERSION so
# lib/calamares can be used as module path for the Python interpreter.
install( CODE "

View File

@ -0,0 +1,59 @@
/* === This file is part of Calamares - <https://github.com/calamares> ===
*
* Copyright 2018, Adriaan de Groot <groot@kde.org>
*
* Calamares is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Calamares is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Calamares. If not, see <http://www.gnu.org/licenses/>.
*/
#include "Tests.h"
#include "utils/Logger.h"
#include <QtTest/QtTest>
QTEST_GUILESS_MAIN( LibCalamaresTests )
LibCalamaresTests::LibCalamaresTests()
{
}
LibCalamaresTests::~LibCalamaresTests()
{
}
void
LibCalamaresTests::initTestCase()
{
}
void
LibCalamaresTests::testDebugLevels()
{
Logger::setupLogLevel( Logger::LOG_DISABLE );
QCOMPARE( Logger::logLevel(), static_cast<unsigned int>( Logger::LOG_DISABLE ) );
for ( unsigned int level = 0; level <= Logger::LOGVERBOSE ; ++level )
{
Logger::setupLogLevel( level );
QCOMPARE( Logger::logLevel(), level );
QVERIFY( Logger::logLevelEnabled( level ) );
for ( unsigned int xlevel = 0; xlevel <= Logger::LOGVERBOSE; ++xlevel )
{
QCOMPARE( Logger::logLevelEnabled( xlevel ), xlevel <= level );
}
}
}

36
src/libcalamares/Tests.h Normal file
View File

@ -0,0 +1,36 @@
/* === This file is part of Calamares - <https://github.com/calamares> ===
*
* Copyright 2018, Adriaan de Groot <groot@kde.org>
*
* Calamares is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Calamares is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Calamares. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef TESTS_H
#define TESTS_H
#include <QObject>
class LibCalamaresTests : public QObject
{
Q_OBJECT
public:
LibCalamaresTests();
~LibCalamaresTests() override;
private Q_SLOTS:
void initTestCase();
void testDebugLevels();
};
#endif

View File

@ -49,6 +49,9 @@ static QTranslator* s_brandingTranslator = nullptr;
static QTranslator* s_translator = nullptr;
static QString s_translatorLocaleName;
static bool s_haveExtraDirs = false;
static QStringList s_extraConfigDirs;
static QStringList s_extraDataDirs;
static bool
isWritableDir( const QDir& dir )
@ -94,6 +97,46 @@ setAppDataDir( const QDir& dir )
s_isAppDataDirOverridden = true;
}
/* Split $ENV{@p name} on :, append to @p l, making sure each ends in / */
static void
mungeEnvironment( QStringList& l, const char *name )
{
for ( auto s : QString( qgetenv( name ) ).split(':') )
if ( s.endsWith( '/' ) )
l << s;
else
l << ( s + '/' );
}
void
setXdgDirs()
{
s_haveExtraDirs = true;
mungeEnvironment( s_extraConfigDirs, "XDG_CONFIG_DIRS" );
mungeEnvironment( s_extraDataDirs, "XDG_DATA_DIRS" );
}
QStringList
extraConfigDirs()
{
if ( s_haveExtraDirs )
return s_extraConfigDirs;
return QStringList();
}
QStringList
extraDataDirs()
{
if ( s_haveExtraDirs )
return s_extraDataDirs;
return QStringList();
}
bool
haveExtraDirs()
{
return s_haveExtraDirs && ( !s_extraConfigDirs.isEmpty() || !s_extraDataDirs.isEmpty() );
}
bool
isAppDataDirOverridden()

View File

@ -79,6 +79,16 @@ namespace CalamaresUtils
DLLEXPORT void setQmlModulesDir( const QDir& dir );
/** @brief Setup extra config and data dirs from the XDG variables.
*/
DLLEXPORT void setXdgDirs();
/** @brief Are any extra directories configured? */
DLLEXPORT bool haveExtraDirs();
/** @brief XDG_CONFIG_DIRS, each guaranteed to end with / */
DLLEXPORT QStringList extraConfigDirs();
/** @brief XDG_DATA_DIRS, each guaranteed to end with / */
DLLEXPORT QStringList extraDataDirs();
/**
* @brief removeDiacritics replaces letters with diacritics and ligatures with
* alternative forms and digraphs.

View File

@ -55,6 +55,18 @@ setupLogLevel(unsigned int level)
s_threshold = level + 1; // Comparison is < in log() function
}
bool
logLevelEnabled(unsigned int level)
{
return level < s_threshold;
}
unsigned int
logLevel()
{
return s_threshold > 0 ? s_threshold - 1 : 0;
}
static void
log( const char* msg, unsigned int debugLevel, bool toDisk = true )
{

View File

@ -89,6 +89,12 @@ namespace Logger
*/
DLLEXPORT void setupLogLevel( unsigned int level );
/** @brief Return the configured log-level. */
DLLEXPORT unsigned int logLevel();
/** @brief Would the given @p level really be logged? */
DLLEXPORT bool logLevelEnabled( unsigned int level );
/**
* @brief Row-oriented formatted logging.
*

View File

@ -145,8 +145,19 @@ moduleConfigurationCandidates( bool assumeBuildDir, const QString& moduleName, c
paths << CalamaresUtils::appDataDir().absoluteFilePath( QString( "modules/%1" ).arg( configFileName ) );
else
{
// If an absolute path is given, in debug mode, look for it
// first. The case contains('/'), below, will add the absolute
// path a second time, though.
if ( assumeBuildDir && configFileName.startsWith( '/' ) )
paths << configFileName;
if ( assumeBuildDir )
paths << QDir().absoluteFilePath(QString( "src/modules/%1/%2" ).arg( moduleName ).arg( configFileName ) );
if ( assumeBuildDir && configFileName.contains( '/' ) )
paths << QDir().absoluteFilePath( configFileName );
if ( CalamaresUtils::haveExtraDirs() )
for ( auto s : CalamaresUtils::extraConfigDirs() )
paths << ( s + QString( "modules/%1" ).arg( configFileName ) );
paths << QString( "/etc/calamares/modules/%1" ).arg( configFileName );
paths << CalamaresUtils::appDataDir().absoluteFilePath( QString( "modules/%1" ).arg( configFileName ) );
@ -168,6 +179,7 @@ Module::loadConfigurationFile( const QString& configFileName ) //throws YAML::Ex
YAML::Node doc = YAML::Load( ba.constData() );
if ( doc.IsNull() )
{
cDebug() << "Found empty module configuration" << path;
// Special case: empty config files are valid,
// but aren't a map.
return;
@ -178,14 +190,13 @@ Module::loadConfigurationFile( const QString& configFileName ) //throws YAML::Ex
return;
}
cDebug() << "Loaded module configuration" << path;
m_configurationMap = CalamaresUtils::yamlMapToVariant( doc ).toMap();
m_emergency = m_maybe_emergency
&& m_configurationMap.contains( EMERGENCY )
&& m_configurationMap[ EMERGENCY ].toBool();
return;
}
else
continue;
}
}

View File

@ -8,10 +8,7 @@ calamares_add_plugin( contextualprocess
SHARED_LIB
)
if( ECM_FOUND )
find_package( Qt5 COMPONENTS Test REQUIRED )
include( ECMAddTests )
if( ECM_FOUND AND BUILD_TESTING )
ecm_add_test(
Tests.cpp
ContextualProcessJob.cpp # Builds it a second time

View File

@ -8,9 +8,9 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2017-09-04 08:16-0400\n"
"POT-Creation-Date: 2018-06-18 07:46-0400\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: Mingcong Bai <jeffbai@aosc.xyz>, 2017\n"
"Last-Translator: soenggam <senggemg@gmail.com>, 2017\n"
"Language-Team: Chinese (China) (https://www.transifex.com/calamares/teams/20061/zh_CN/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
@ -24,7 +24,7 @@ msgstr "按我按我!"
#: src/modules/dummypythonqt/main.py:94
msgid "A new QLabel."
msgstr "一个平淡无奇的 QLabel。"
msgstr "一个新的QLabel。"
#: src/modules/dummypythonqt/main.py:97
msgid "Dummy PythonQt ViewStep"

View File

@ -0,0 +1,41 @@
find_package( KPMcore 3.3 )
find_package( Qt5 REQUIRED DBus ) # Needed for KPMCore
find_package( KF5 REQUIRED I18n WidgetsAddons ) # Needed for KPMCore
if ( KPMcore_FOUND )
include_directories( ${KPMCORE_INCLUDE_DIR} )
include_directories( ${PROJECT_BINARY_DIR}/src/libcalamares )
# The PartitionIterator is a small class, and it's easiest -- but also a
# gross hack -- to just compile it again from the partition module tree.
calamares_add_plugin( fsresizer
TYPE job
EXPORT_MACRO PLUGINDLLEXPORT_PRO
SOURCES
ResizeFSJob.cpp
${PROJECT_SOURCE_DIR}/src/modules/partition/core/PartitionIterator.cpp
LINK_PRIVATE_LIBRARIES
kpmcore
calamares
SHARED_LIB
)
if( ECM_FOUND AND BUILD_TESTING )
ecm_add_test(
Tests.cpp
TEST_NAME
fsresizertest
LINK_LIBRARIES
${CALAMARES_LIBRARIES}
calamares
calamares_job_fsresizer # From above
${YAMLCPP_LIBRARY}
Qt5::Core
Qt5::Test
)
set_target_properties( fsresizertest PROPERTIES AUTOMOC TRUE )
target_include_directories(fsresizertest PRIVATE /usr/local/include )
endif()
else()
calamares_skip_module( "fsresizer (missing suitable KPMcore)" )
endif()

View File

@ -0,0 +1,347 @@
/* === This file is part of Calamares - <https://github.com/calamares> ===
*
* Copyright 2018, Adriaan de Groot <groot@kde.org>
*
* Calamares is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Calamares is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Calamares. If not, see <http://www.gnu.org/licenses/>.
*/
#include "ResizeFSJob.h"
#include <QProcess>
#include <QDateTime>
#include <QThread>
#include <kpmcore/backend/corebackend.h>
#include <kpmcore/backend/corebackendmanager.h>
#include <kpmcore/core/device.h>
#include <kpmcore/core/partition.h>
#include <kpmcore/ops/resizeoperation.h>
#include <kpmcore/util/report.h>
#include "CalamaresVersion.h"
#include "JobQueue.h"
#include "GlobalStorage.h"
#include "utils/CalamaresUtils.h"
#include "utils/Logger.h"
#include "utils/Units.h"
#include "modules/partition/core/PartitionIterator.h"
ResizeFSJob::RelativeSize::RelativeSize()
: m_value( 0 )
, m_unit( None )
{
}
template<int N>
void matchUnitSuffix(
const QString& s,
const char ( &suffix )[N],
ResizeFSJob::RelativeSize::Unit matchedUnit,
int& value,
ResizeFSJob::RelativeSize::Unit& unit
)
{
if ( s.endsWith( suffix ) )
{
value = s.left( s.length() - N + 1 ).toInt();
unit = matchedUnit;
}
}
ResizeFSJob::RelativeSize::RelativeSize( const QString& s )
: m_value( 0 )
, m_unit( None )
{
matchUnitSuffix( s, "%", Percent, m_value, m_unit );
matchUnitSuffix( s, "MiB", Absolute, m_value, m_unit );
if ( ( unit() == Percent ) && ( value() > 100 ) )
{
cDebug() << "Percent value" << value() << "is not valid.";
m_value = 0;
m_unit = None;
}
if ( !m_value )
m_unit = None;
}
qint64
ResizeFSJob::RelativeSize::apply( qint64 totalSectors, qint64 sectorSize )
{
if ( !isValid() )
return -1;
if ( sectorSize < 1 )
return -1;
switch ( m_unit )
{
case None:
return -1;
case Absolute:
return CalamaresUtils::MiBtoBytes( value() ) / sectorSize;
case Percent:
if ( value() == 100 )
return totalSectors; // Common-case, avoid futzing around
else
return totalSectors * value() / 100;
}
// notreached
return -1;
}
qint64
ResizeFSJob::RelativeSize::apply( Device* d )
{
return apply( d->totalLogical(), d->logicalSize() );
}
ResizeFSJob::ResizeFSJob( QObject* parent )
: Calamares::CppJob( parent )
, m_required( false )
{
}
ResizeFSJob::~ResizeFSJob()
{
}
QString
ResizeFSJob::prettyName() const
{
return tr( "Resize Filesystem Job" );
}
ResizeFSJob::PartitionMatch
ResizeFSJob::findPartition( CoreBackend* backend )
{
using DeviceList = QList< Device* >;
DeviceList devices = backend->scanDevices( false );
cDebug() << "ResizeFSJob found" << devices.count() << "devices.";
for ( DeviceList::iterator dev_it = devices.begin(); dev_it != devices.end(); ++dev_it )
{
if ( ! ( *dev_it ) )
continue;
cDebug() << "ResizeFSJob found" << ( *dev_it )->deviceNode();
for ( auto part_it = PartitionIterator::begin( *dev_it ); part_it != PartitionIterator::end( *dev_it ); ++part_it )
{
cDebug() << ".." << ( *part_it )->mountPoint() << "on" << ( *part_it )->deviceNode();
if ( ( !m_fsname.isEmpty() && ( *part_it )->mountPoint() == m_fsname ) ||
( !m_devicename.isEmpty() && ( *part_it )->deviceNode() == m_devicename ) )
{
cDebug() << ".. matched configuration dev=" << m_devicename << "fs=" << m_fsname;
return PartitionMatch( *dev_it, *part_it );
}
}
}
cDebug() << "No match for configuration dev=" << m_devicename << "fs=" << m_fsname;
return PartitionMatch( nullptr, nullptr );
}
/** @brief Returns the last sector the matched partition should occupy.
*
* Returns a sector number. Returns -1 if something is wrong (e.g.
* can't resize at all, or missing data). Returns 0 if the resize
* won't fit because it doesn't satisfy the settings for atleast
* and size (or won't grow at all because the partition is blocked
* by occupied space after it).
*/
qint64
ResizeFSJob::findGrownEnd( ResizeFSJob::PartitionMatch m )
{
if ( !m.first || !m.second )
return -1; // Missing device data
if ( !ResizeOperation::canGrow( m.second ) )
return -1; // Operation is doomed
if ( !m_size.isValid() )
return -1; // Must have a grow-size
cDebug() << "Containing device size" << m.first->totalLogical();
qint64 last_available = m.first->totalLogical() - 1; // Numbered from 0
qint64 last_currently = m.second->lastSector();
cDebug() << "Growing partition" << m.second->firstSector() << '-' << last_currently;
for ( auto part_it = PartitionIterator::begin( m.first ); part_it != PartitionIterator::end( m.first ); ++part_it )
{
qint64 next_start = ( *part_it )->firstSector();
qint64 next_end = ( *part_it )->lastSector();
if ( next_start > next_end )
{
cWarning() << "Corrupt partition has end" << next_end << " < start" << next_start;
std::swap( next_start, next_end );
}
if ( ( *part_it )->roles().has( PartitionRole::Unallocated ) )
{
cDebug() << ".. ignoring unallocated" << next_start << '-' << next_end;
continue;
}
cDebug() << ".. comparing" << next_start << '-' << next_end;
if ( ( next_start > last_currently ) && ( next_start < last_available ) )
{
cDebug() << " .. shrunk last available to" << next_start;
last_available = next_start - 1; // Before that one starts
}
}
if ( !( last_available > last_currently ) )
{
cDebug() << "Partition cannot grow larger.";
return 0;
}
qint64 expand = last_available - last_currently; // number of sectors
if ( m_atleast.isValid() )
{
qint64 required = m_atleast.apply( m.first );
if ( expand < required )
{
cDebug() << ".. need to expand by" << required << "but only" << expand << "is available.";
return 0;
}
}
qint64 wanted = m_size.apply( expand, m.first->logicalSize() );
if ( wanted < expand )
{
cDebug() << ".. only growing by" << wanted << "instead of full" << expand;
last_available -= ( expand - wanted );
}
return last_available;
}
Calamares::JobResult
ResizeFSJob::exec()
{
if ( !isValid() )
return Calamares::JobResult::error(
tr( "Invalid configuration" ),
tr( "The file-system resize job has an invalid configuration and will not run." ) );
// Get KPMCore
auto backend_p = CoreBackendManager::self()->backend();
if ( backend_p )
cDebug() << "KPMCore backend @" << ( void* )backend_p << backend_p->id() << backend_p->version();
else
{
cDebug() << "No KPMCore backend loaded yet";
QByteArray backendName = qgetenv( "KPMCORE_BACKEND" );
if ( !CoreBackendManager::self()->load( backendName.isEmpty() ? CoreBackendManager::defaultBackendName() : backendName ) )
{
cWarning() << "Could not load KPMCore backend.";
return Calamares::JobResult::error(
tr( "KPMCore not Available" ),
tr( "Calamares cannot start KPMCore for the file-system resize job." ) );
}
backend_p = CoreBackendManager::self()->backend();
}
if ( !backend_p )
{
cWarning() << "Could not load KPMCore backend (2).";
return Calamares::JobResult::error(
tr( "KPMCore not Available" ),
tr( "Calamares cannot start KPMCore for the file-system resize job." ) );
}
backend_p->initFSSupport(); // Might not be enough, see below
// Now get the partition and FS we want to work on
PartitionMatch m = findPartition( backend_p );
if ( !m.first || !m.second )
return Calamares::JobResult::error(
tr( "Resize Failed" ),
!m_fsname.isEmpty() ? tr( "The filesystem %1 could not be found in this system, and cannot be resized." ).arg( m_fsname )
: tr( "The device %1 could not be found in this system, and cannot be resized." ).arg( m_devicename ) );
m.second->fileSystem().init(); // Initialize support for specific FS
if ( !ResizeOperation::canGrow( m.second ) )
{
cDebug() << "canGrow() returned false.";
return Calamares::JobResult::error(
tr( "Resize Failed" ),
!m_fsname.isEmpty() ? tr( "The filesystem %1 cannot be resized." ).arg( m_fsname )
: tr( "The device %1 cannot be resized." ).arg( m_devicename ) );
}
qint64 new_end = findGrownEnd( m );
cDebug() << "Resize from"
<< m.second->firstSector() << '-' << m.second->lastSector()
<< '(' << m.second->length() << ')'
<< "to -" << new_end;
if ( new_end < 0 )
return Calamares::JobResult::error(
tr( "Resize Failed" ),
!m_fsname.isEmpty() ? tr( "The filesystem %1 cannot be resized." ).arg( m_fsname )
: tr( "The device %1 cannot be resized." ).arg( m_devicename ) );
if ( new_end == 0 )
{
cWarning() << "Resize operation on" << m_fsname << m_devicename
<< "skipped as not-useful.";
if ( m_required )
return Calamares::JobResult::error(
tr( "Resize Failed" ),
!m_fsname.isEmpty() ? tr( "The filesystem %1 must be resized, but cannot." ).arg( m_fsname )
: tr( "The device %1 must be resized, but cannot" ).arg( m_fsname ) );
return Calamares::JobResult::ok();
}
if ( ( new_end > 0 ) && ( new_end > m.second->lastSector() ) )
{
ResizeOperation op( *m.first, *m.second, m.second->firstSector(), new_end );
Report op_report( nullptr );
if ( op.execute( op_report ) )
cDebug() << "Resize operation OK.";
else
{
cDebug() << "Resize failed." << op_report.output();
return Calamares::JobResult::error(
tr( "Resize Failed" ),
op_report.toText() );
}
}
return Calamares::JobResult::ok();
}
void
ResizeFSJob::setConfigurationMap( const QVariantMap& configurationMap )
{
m_fsname = configurationMap["fs"].toString();
m_devicename = configurationMap["dev"].toString();
if ( m_fsname.isEmpty() && m_devicename.isEmpty() )
{
cWarning() << "No fs or dev configured for resize.";
return;
}
m_size = RelativeSize( configurationMap["size"].toString() );
m_atleast = RelativeSize( configurationMap["atleast"].toString() );
m_required = CalamaresUtils::getBool( configurationMap, "required", false );
}
CALAMARES_PLUGIN_FACTORY_DEFINITION( ResizeFSJobFactory, registerPlugin<ResizeFSJob>(); )

View File

@ -0,0 +1,122 @@
/* === This file is part of Calamares - <https://github.com/calamares> ===
*
* Copyright 2018, Adriaan de Groot <groot@kde.org>
*
* Calamares is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Calamares is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Calamares. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef RESIZEFSJOB_H
#define RESIZEFSJOB_H
#include <QObject>
#include <QVariantMap>
#include <CppJob.h>
#include <utils/PluginFactory.h>
#include <PluginDllMacro.h>
class CoreBackend; // From KPMCore
class Device; // From KPMCore
class Partition;
class PLUGINDLLEXPORT ResizeFSJob : public Calamares::CppJob
{
Q_OBJECT
public:
/** @brief Size expressions
*
* Sizes can be specified in MiB or percent (of the device they
* are on). This class handles parsing of such strings from the
* config file.
*/
class RelativeSize
{
public:
RelativeSize();
RelativeSize( const QString& );
enum Unit
{
None,
Percent,
Absolute
};
int value() const { return m_value; }
Unit unit() const { return m_unit; }
bool isValid() const
{
return ( unit() != None ) && ( value() > 0 );
}
/** @brief Apply this size to the number of sectors @p totalSectors .
*
* Each sector has size @p sectorSize , for converting absolute
* sizes in MiB to sector counts.
*
* For invalid sizes, returns -1.
* For absolute sizes, returns the number of sectors needed.
* For percent sizes, returns that percent of the number of sectors.
*/
qint64 apply( qint64 totalSectors, qint64 sectorSize );
/** @brief Apply this size to the given device.
*
* Equivalent to apply( d->totalLogical(), d->logicalSize() )
*/
qint64 apply( Device* d );
private:
int m_value;
Unit m_unit;
} ;
explicit ResizeFSJob( QObject* parent = nullptr );
virtual ~ResizeFSJob() override;
QString prettyName() const override;
Calamares::JobResult exec() override;
void setConfigurationMap( const QVariantMap& configurationMap ) override;
/** @brief Is the configuration of this job valid? */
bool isValid() const
{
return ( !m_fsname.isEmpty() || !m_devicename.isEmpty() ) &&
m_size.isValid();
}
private:
RelativeSize m_size;
RelativeSize m_atleast;
QString m_fsname; // Either this, or devicename, is set, not both
QString m_devicename;
bool m_required;
using PartitionMatch = QPair<Device*, Partition*>;
/** @brief Find the configured FS using KPMCore @p backend */
PartitionMatch findPartition( CoreBackend* backend );
/** @brief Return a new end-sector for the given dev-part pair. */
qint64 findGrownEnd( PartitionMatch );
};
CALAMARES_PLUGIN_FACTORY_DECLARATION( ResizeFSJobFactory )
#endif // RESIZEFSJOB_H

View File

@ -0,0 +1,126 @@
/* === This file is part of Calamares - <https://github.com/calamares> ===
*
* Copyright 2017-2018, Adriaan de Groot <groot@kde.org>
*
* Calamares is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Calamares is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Calamares. If not, see <http://www.gnu.org/licenses/>.
*/
#include "Tests.h"
#include "GlobalStorage.h"
#include "JobQueue.h"
#include "Settings.h"
#include "utils/Logger.h"
#include "utils/YamlUtils.h"
#include <yaml-cpp/yaml.h>
#include <QtTest/QtTest>
#include <QFileInfo>
#include <QStringList>
#define private public
#include "ResizeFSJob.h"
#undef private
QTEST_GUILESS_MAIN( FSResizerTests )
FSResizerTests::FSResizerTests()
{
}
FSResizerTests::~FSResizerTests()
{
}
void
FSResizerTests::initTestCase()
{
}
void FSResizerTests::testConfigurationRobust()
{
ResizeFSJob j;
// Empty config
j.setConfigurationMap( QVariantMap() );
QVERIFY( j.m_fsname.isEmpty() );
QVERIFY( j.m_devicename.isEmpty() );
QCOMPARE( j.m_size.unit(), ResizeFSJob::RelativeSize::None );
QCOMPARE( j.m_atleast.unit(), ResizeFSJob::RelativeSize::None );
// Config is missing fs and dev, so it isn't valid
YAML::Node doc0 = YAML::Load( R"(---
size: 100%
atleast: 600MiB
)" );
j.setConfigurationMap( CalamaresUtils::yamlMapToVariant( doc0 ).toMap() );
QVERIFY( j.m_fsname.isEmpty() );
QVERIFY( j.m_devicename.isEmpty() );
QCOMPARE( j.m_size.unit(), ResizeFSJob::RelativeSize::None );
QCOMPARE( j.m_atleast.unit(), ResizeFSJob::RelativeSize::None );
QCOMPARE( j.m_size.value(), 0 );
QCOMPARE( j.m_atleast.value(), 0 );
}
void FSResizerTests::testConfigurationValues()
{
ResizeFSJob j;
// Check both
YAML::Node doc0 = YAML::Load( R"(---
fs: /
size: 100%
atleast: 600MiB
)" );
j.setConfigurationMap( CalamaresUtils::yamlMapToVariant( doc0 ).toMap() );
QVERIFY( !j.m_fsname.isEmpty() );
QVERIFY( j.m_devicename.isEmpty() );
QCOMPARE( j.m_size.unit(), ResizeFSJob::RelativeSize::Percent );
QCOMPARE( j.m_atleast.unit(), ResizeFSJob::RelativeSize::Absolute );
QCOMPARE( j.m_size.value(), 100 );
QCOMPARE( j.m_atleast.value(), 600 );
// Silly config
doc0 = YAML::Load( R"(---
fs: /
dev: /dev/m00
size: 72 MiB
atleast: 127 %
)" );
j.setConfigurationMap( CalamaresUtils::yamlMapToVariant( doc0 ).toMap() );
QVERIFY( !j.m_fsname.isEmpty() );
QVERIFY( !j.m_devicename.isEmpty() );
QCOMPARE( j.m_size.unit(), ResizeFSJob::RelativeSize::Absolute );
QCOMPARE( j.m_atleast.unit(), ResizeFSJob::RelativeSize::Percent );
QCOMPARE( j.m_size.value(), 72 );
QCOMPARE( j.m_atleast.value(), 127 );
// Silly config
doc0 = YAML::Load( R"(---
fs: /
# dev: /dev/m00
size: 71MiB
# atleast: 127%
)" );
j.setConfigurationMap( CalamaresUtils::yamlMapToVariant( doc0 ).toMap() );
QVERIFY( !j.m_fsname.isEmpty() );
QVERIFY( j.m_devicename.isEmpty() );
QCOMPARE( j.m_size.unit(), ResizeFSJob::RelativeSize::Absolute );
QCOMPARE( j.m_atleast.unit(), ResizeFSJob::RelativeSize::None );
QCOMPARE( j.m_size.value(), 71 );
QCOMPARE( j.m_atleast.value(), 0 );
}

View File

@ -0,0 +1,39 @@
/* === This file is part of Calamares - <https://github.com/calamares> ===
*
* Copyright 2018, Adriaan de Groot <groot@kde.org>
*
* Calamares is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Calamares is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Calamares. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef TESTS_H
#define TESTS_H
#include <QObject>
class FSResizerTests : public QObject
{
Q_OBJECT
public:
FSResizerTests();
~FSResizerTests() override;
private Q_SLOTS:
void initTestCase();
// Can handle missing values
void testConfigurationRobust();
// Can parse % and MiB values
void testConfigurationValues();
};
#endif

View File

@ -0,0 +1,49 @@
# Module that resizes a single FS to fill the entire (rest) of
# a device. This is used in OEM situations where an image is
# flashed onto an SD card (or similar) and used to boot a device,
# after which the FS should expand to fill the SD card.
#
# Example: a distro produces a 6GiB large image that is
# written to an 8GiB SD card; the FS should expand to take
# advantage of the unused 2GiB. The FS should expand much
# more if the same image is written to a 16GiB card.
---
# Which FS needs to be grown? Choose one way to identify it:
# - *fs* names a mount point which should already be mounted
# in the system.
# - *dev* names a device
fs: /
# dev: /dev/mmcblk0p1
# How much of the total remaining space should the FS use?
# The only sensible amount is "all of it". The value is
# in percent, so set it to 100. Perhaps a fixed size is
# needed (that would be weird though, since you don't know
# how big the card is), use MiB as suffix in that case.
# If missing, then it's assumed to be 0, and no resizing
# will happen.
#
# Percentages apply to **available space**.
size: 100%
# Resizing might not be worth it, though. Set the minimum
# that it must grow; if it cannot grow that much, the
# resizing is skipped. Can be in percentage or absolute
# size, as above. If missing, then it's assumed to be 0,
# which means resizing is always worthwhile.
#
# If *atleast* is not zero, then the setting *required*,
# below, becomes relevant.
#
# Percentages apply to **total device size**.
#atleast: 1000MiB
# When *atleast* is not zero, then the resize may be
# recommended (the default) or **required**. If the
# resize is required and cannot be carried out (because
# there's not enough space), then that is a fatal
# error for the installer. By default, resize is only
# recommended and it is not an error for no resize to be
# carried out.
required: false

View File

@ -65,6 +65,8 @@ SetKeyboardLayoutJob::prettyName() const
QString
SetKeyboardLayoutJob::findConvertedKeymap( const QString& convertedKeymapPath ) const
{
cDebug() << "Looking for converted keymap in" << convertedKeymapPath;
// No search path supplied, assume the distribution does not provide
// converted keymaps
if ( convertedKeymapPath.isEmpty() )
@ -76,8 +78,7 @@ SetKeyboardLayoutJob::findConvertedKeymap( const QString& convertedKeymapPath )
if ( convertedKeymapDir.exists( name + ".map" )
|| convertedKeymapDir.exists( name + ".map.gz" ) )
{
cDebug() << "Found converted keymap" << name;
cDebug() << ".. Found converted keymap" << name;
return name;
}
@ -88,6 +89,8 @@ SetKeyboardLayoutJob::findConvertedKeymap( const QString& convertedKeymapPath )
QString
SetKeyboardLayoutJob::findLegacyKeymap() const
{
cDebug() << "Looking for legacy keymap in QRC";
int bestMatching = 0;
QString name;
@ -137,7 +140,7 @@ SetKeyboardLayoutJob::findLegacyKeymap() const
// The best matching entry so far, then let's save that
if ( matching >= qMax( bestMatching, 1 ) )
{
cDebug() << "Found legacy keymap" << mapping[0]
cDebug() << ".. Found legacy keymap" << mapping[0]
<< "with score" << matching;
if ( matching > bestMatching )

View File

@ -6,6 +6,9 @@
# This is the version from 534644b7be7b240eb0fbbe06e20cbecbe8206767,
# committed 2015-01-22 01:07:24 .
#
# Updates:
# - 2018-09-26 Added "Austrian" keyboard (de at). Issue #1035
#
# Generated from system-config-keyboard's model list
# consolelayout xlayout xmodel xvariant xoptions
sg ch pc105 de_nodeadkeys terminate:ctrl_alt_bksp
@ -14,8 +17,8 @@ mk-utf mk,us pc105 - terminate:ctrl_alt_bksp,grp:shifts_toggle,grp_led:scrol
trq tr pc105 - terminate:ctrl_alt_bksp
uk gb pc105 - terminate:ctrl_alt_bksp
is-latin1 is pc105 - terminate:ctrl_alt_bksp
at de pc105 - terminate:ctrl_alt_bksp
de de pc105 - terminate:ctrl_alt_bksp
de at pc105 - terminate:ctrl_alt_bksp
la-latin1 latam pc105 - terminate:ctrl_alt_bksp
us us pc105+inet - terminate:ctrl_alt_bksp
ko kr pc105 - terminate:ctrl_alt_bksp

View File

@ -1,9 +1,3 @@
find_package(ECM ${ECM_VERSION} NO_MODULE)
if( ECM_FOUND AND BUILD_TESTING )
include( ECMAddTests )
find_package( Qt5 COMPONENTS Core Test REQUIRED )
endif()
# When debugging the timezone widget, add this debugging definition
# to have a debugging-friendly timezone widget, debug logging,
# and no intrusive timezone-setting while clicking around.

View File

@ -134,7 +134,7 @@ def run():
if os.path.exists(target_locale_gen_bak):
shutil.copy2(target_locale_gen_bak, target_locale_gen)
libcalamares.utils.debug("Restored backup {!s} -> {!s}"
.format(target_locale_gen_bak).format(target_locale_gen))
.format(target_locale_gen_bak, target_locale_gen))
# run locale-gen if detected; this *will* cause an exception
# if the live system has locale.gen, but the target does not:

View File

@ -113,28 +113,32 @@ QList< Device* > getDevices( DeviceType which, qint64 minimumSize )
// Remove the device which contains / from the list
for ( DeviceList::iterator it = devices.begin(); it != devices.end(); )
if ( ! ( *it ) ||
( *it )->deviceNode().startsWith( "/dev/zram" )
if ( !( *it ) )
{
cDebug() << " .. Skipping nullptr device";
it = erase( devices, it);
}
else if ( ( *it )->deviceNode().startsWith( "/dev/zram" )
)
{
cDebug() << " .. Removing zram" << it;
it = erase(devices, it );
it = erase( devices, it );
}
else if ( writableOnly && hasRootPartition( *it ) )
{
cDebug() << " .. Removing device with root filesystem (/) on it" << it;
it = erase(devices, it );
it = erase( devices, it );
}
else if ( writableOnly && isIso9660( *it ) )
{
cDebug() << " .. Removing device with iso9660 filesystem (probably a CD) on it" << it;
it = erase(devices, it );
it = erase( devices, it );
}
else if ( (minimumSize >= 0) && !( (*it)->capacity() > minimumSize ) )
{
cDebug() << " .. Removing too-small" << it;
it = erase(devices, it );
it = erase( devices, it );
}
else
++it;

View File

@ -509,18 +509,8 @@ PartitionCoreModule::jobs() const
lst << info->jobs;
devices << info->device.data();
}
cDebug() << "Creating FillGlobalStorageJob with bootLoader path" << m_bootLoaderInstallPath;
lst << Calamares::job_ptr( new FillGlobalStorageJob( devices, m_bootLoaderInstallPath ) );
QStringList jobsDebug;
foreach ( auto job, lst )
jobsDebug.append( job->prettyName() );
cDebug() << "PartitionCodeModule has been asked for jobs. About to return:";
for ( const auto item: jobsDebug )
cDebug() << " .." << item;
return lst;
}
@ -573,9 +563,9 @@ PartitionCoreModule::dumpQueue() const
cDebug() << "# Queue:";
for ( auto info : m_deviceInfos )
{
cDebug() << " .. Device:" << info->device->name();
cDebug() << "## Device:" << info->device->name();
for ( auto job : info->jobs )
cDebug() << " .." << job->prettyName();
cDebug() << "-" << job->prettyName();
}
}

View File

@ -18,7 +18,7 @@
* along with Calamares. If not, see <http://www.gnu.org/licenses/>.
*/
#include <core/PartitionIterator.h>
#include "PartitionIterator.h"
// KPMcore
#include <kpmcore/core/device.h>

View File

@ -1161,6 +1161,13 @@ force_uncheck(QButtonGroup* grp, PrettyRadioButton* button)
grp->setExclusive( true );
}
static inline QDebug&
operator <<( QDebug& s, PartitionIterator& it )
{
s << ( ( *it ) ? ( *it )->deviceNode() : QString( "<null device>" ) );
return s;
}
/**
* @brief ChoicePage::setupActions happens every time a new Device* is selected in the
* device picker. Sets up the text and visibility of the partitioning actions based
@ -1174,6 +1181,9 @@ ChoicePage::setupActions()
OsproberEntryList osproberEntriesForCurrentDevice =
getOsproberEntriesForDevice( currentDevice );
cDebug() << "Setting up actions for" << currentDevice->deviceNode()
<< "with" << osproberEntriesForCurrentDevice.count() << "entries.";
if ( currentDevice->partitionTable() )
m_deviceInfoWidget->setPartitionTableType( currentDevice->partitionTable()->type() );
else
@ -1190,18 +1200,30 @@ ChoicePage::setupActions()
#ifdef WITH_KPMCOREGT33
if ( currentDevice->type() == Device::Type::SoftwareRAID_Device &&
static_cast< SoftwareRAID* >(currentDevice)->status() == SoftwareRAID::Status::Inactive )
{
cDebug() << ".. part of an inactive RAID device";
isInactiveRAID = true;
}
#endif
for ( auto it = PartitionIterator::begin( currentDevice );
it != PartitionIterator::end( currentDevice ); ++it )
{
if ( PartUtils::canBeResized( *it ) )
{
cDebug() << ".. contains resizable" << it;
atLeastOneCanBeResized = true;
}
if ( PartUtils::canBeReplaced( *it ) )
{
cDebug() << ".. contains replacable" << it;
atLeastOneCanBeReplaced = true;
}
if ( (*it)->isMounted() )
{
cDebug() << ".. contains mounted" << it;
atLeastOneIsMounted = true;
}
}
if ( osproberEntriesForCurrentDevice.count() == 0 )
@ -1318,7 +1340,12 @@ ChoicePage::setupActions()
if ( !atLeastOneIsMounted && !isInactiveRAID )
m_eraseButton->show(); // None mounted
else
{
cDebug() << "Erase button suppressed"
<< "mount?" << atLeastOneIsMounted
<< "raid?" << isInactiveRAID;
force_uncheck( m_grp, m_eraseButton );
}
bool isEfi = PartUtils::isEfiSystem();
bool efiSystemPartitionFound = !m_core->efiSystemPartitions().isEmpty();

View File

@ -20,6 +20,8 @@
#include "jobs/CreatePartitionTableJob.h"
#include "core/PartitionIterator.h"
#include "utils/Logger.h"
// KPMcore
@ -65,6 +67,14 @@ CreatePartitionTableJob::prettyStatusMessage() const
}
static inline QDebug&
operator <<( QDebug& s, PartitionIterator& it )
{
s << ( ( *it ) ? ( *it )->deviceNode() : QString( "<null device>" ) );
return s;
}
Calamares::JobResult
CreatePartitionTableJob::exec()
{
@ -73,33 +83,28 @@ CreatePartitionTableJob::exec()
PartitionTable* table = m_device->partitionTable();
cDebug() << "Creating new partition table of type" << table->typeName()
<< " - Uncommitted yet: " << table;
<< ", uncommitted yet:";
QProcess lsblk;
lsblk.setProgram( "lsblk" );
lsblk.setProcessChannelMode( QProcess::MergedChannels );
lsblk.start();
lsblk.waitForFinished();
if ( Logger::logLevelEnabled( Logger::LOGDEBUG ) )
{
for ( auto it = PartitionIterator::begin( table );
it != PartitionIterator::end( table ); ++it )
cDebug() << *it;
QByteArray byte = lsblk.readAllStandardOutput();
QStringList lines = QString(byte).split(("\n"),QString::SkipEmptyParts);
cDebug() << "CreatePartitionTableJob asked for lsblk output:";
QProcess lsblk;
lsblk.setProgram( "lsblk" );
lsblk.setProcessChannelMode( QProcess::MergedChannels );
lsblk.start();
lsblk.waitForFinished();
cDebug() << "lsblk:\n" << lsblk.readAllStandardOutput();
for (const auto line: lines)
cDebug() << " .." << line;
QProcess mount;
mount.setProgram( "mount" );
mount.setProcessChannelMode( QProcess::MergedChannels );
mount.start();
mount.waitForFinished();
QByteArray mbyte = mount.readAllStandardOutput();
QStringList mlines = QString(mbyte).split(("\n"),QString::SkipEmptyParts);
cDebug() << "CreatePartitionTableJob asked for mount output:";
for (const auto mline: mlines)
cDebug() << " .." << mline;
QProcess mount;
mount.setProgram( "mount" );
mount.setProcessChannelMode( QProcess::MergedChannels );
mount.start();
mount.waitForFinished();
cDebug() << "mount:\n" << mount.readAllStandardOutput();
}
CreatePartitionTableOperation op(*m_device, table);
op.setStatus(Operation::StatusRunning);

View File

@ -56,9 +56,12 @@ findPartitionUuids( QList < Device* > devices )
QString path = p->partitionPath();
QString uuid = p->fileSystem().readUUID( p->partitionPath() );
hash.insert( path, uuid );
cDebug() << ".. added path=" << path << "UUID=" << uuid;
}
}
cDebug() << hash;
if ( hash.isEmpty() )
cDebug() << ".. no UUIDs found.";
return hash;
}
@ -90,10 +93,16 @@ mapForPartition( Partition* partition, const QString& uuid )
dynamic_cast< FS::luks& >( partition->fileSystem() ).innerFS() )
map[ "fs" ] = dynamic_cast< FS::luks& >( partition->fileSystem() ).innerFS()->name();
map[ "uuid" ] = uuid;
cDebug() << partition->partitionPath()
<< "mtpoint:" << PartitionInfo::mountPoint( partition )
<< "fs:" << map[ "fs" ] << '(' << map[ "fsName" ] << ')'
<< uuid;
// Debugging for inside the loop in createPartitionList(),
// so indent a bit
Logger::CLog deb = cDebug();
using TR = Logger::DebugRow<const char *const, const QString&>;
deb << " .. mapping for" << partition->partitionPath() << partition->deviceNode()
<< TR( "mtpoint:", PartitionInfo::mountPoint( partition ) )
<< TR( "fs:", map[ "fs" ].toString() )
<< TR( "fsname", map[ "fsName" ].toString() )
<< TR( "uuid", uuid );
if ( partition->roles().has( PartitionRole::Luks ) )
{
@ -104,7 +113,7 @@ mapForPartition( Partition* partition, const QString& uuid )
map[ "luksMapperName" ] = luksFs->mapperName().split( "/" ).last();
map[ "luksUuid" ] = getLuksUuid( partition->partitionPath() );
map[ "luksPassphrase" ] = luksFs->passphrase();
cDebug() << "luksMapperName:" << map[ "luksMapperName" ];
deb << TR( "luksMapperName:", map[ "luksMapperName" ].toString() );
}
}
@ -215,9 +224,11 @@ FillGlobalStorageJob::createPartitionList() const
cDebug() << "Writing to GlobalStorage[\"partitions\"]";
for ( auto device : m_devices )
{
cDebug() << ".. partitions on" << device->deviceNode();
for ( auto it = PartitionIterator::begin( device );
it != PartitionIterator::end( device ); ++it )
{
// Debug-logging is done when creating the map
lst << mapForPartition( *it, hash.value( ( *it )->partitionPath() ) );
}
}

View File

@ -132,6 +132,10 @@ SetPartFlagsJob::prettyStatusMessage() const
Calamares::JobResult
SetPartFlagsJob::exec()
{
cDebug() << "Setting flags on" << m_device->deviceNode()
<< "partition" << partition()->deviceNode()
<< "to" << m_flags;
Report report ( nullptr );
SetPartFlagsOperation op( *m_device, *partition(), m_flags );
op.setStatus( Operation::StatusRunning );

View File

@ -1,6 +1,4 @@
find_package( Qt5 COMPONENTS Gui Test REQUIRED )
include( ECMAddTests )
find_package( Qt5 COMPONENTS Gui REQUIRED )
set( PartitionModule_SOURCE_DIR .. )
@ -23,13 +21,15 @@ include_directories(
${CMAKE_CURRENT_BINARY_DIR}
)
ecm_add_test( ${partitionjobtests_SRCS}
TEST_NAME partitionjobtests
LINK_LIBRARIES
${CALAMARES_LIBRARIES}
kpmcore
Qt5::Core
Qt5::Test
)
if( ECM_FOUND AND BUILD_TESTING )
ecm_add_test( ${partitionjobtests_SRCS}
TEST_NAME partitionjobtests
LINK_LIBRARIES
${CALAMARES_LIBRARIES}
kpmcore
Qt5::Core
Qt5::Test
)
set_target_properties( partitionjobtests PROPERTIES AUTOMOC TRUE )
set_target_properties( partitionjobtests PROPERTIES AUTOMOC TRUE )
endif()

View File

@ -4,6 +4,7 @@ calamares_add_plugin( preservefiles
TYPE job
EXPORT_MACRO PLUGINDLLEXPORT_PRO
SOURCES
permissions.cpp
PreserveFiles.cpp
LINK_PRIVATE_LIBRARIES
calamares

View File

@ -18,6 +18,8 @@
#include "PreserveFiles.h"
#include "permissions.h"
#include "CalamaresVersion.h"
#include "JobQueue.h"
#include "GlobalStorage.h"
@ -83,6 +85,38 @@ PreserveFiles::prettyName() const
return tr( "Saving files for later ..." );
}
static bool
copy_file( const QString& source, const QString& dest )
{
QFile sourcef( source );
if ( !sourcef.open( QFile::ReadOnly ) )
{
cWarning() << "Could not read" << source;
return false;
}
QFile destf( dest );
if ( !destf.open( QFile::WriteOnly ) )
{
sourcef.close();
cWarning() << "Could not open" << destf.fileName() << "for writing; could not copy" << source;
return false;
}
QByteArray b;
do
{
b = sourcef.read( 1_MiB );
destf.write( b );
}
while ( b.count() > 0 );
sourcef.close();
destf.close();
return true;
}
Calamares::JobResult PreserveFiles::exec()
{
if ( m_items.isEmpty() )
@ -96,7 +130,8 @@ Calamares::JobResult PreserveFiles::exec()
for ( const auto& it : m_items )
{
QString source = it.source;
QString dest = prefix + atReplacements( it.dest );
QString bare_dest = atReplacements( it.dest );
QString dest = prefix + bare_dest;
if ( it.type == ItemType::Log )
source = Logger::logFile();
@ -111,32 +146,29 @@ Calamares::JobResult PreserveFiles::exec()
cWarning() << "Skipping unnamed source file for" << dest;
else
{
QFile sourcef( source );
if ( !sourcef.open( QFile::ReadOnly ) )
if ( copy_file( source, dest ) )
{
cWarning() << "Could not read" << source;
continue;
if ( it.perm.isValid() )
{
auto s_p = CalamaresUtils::System::instance();
int r;
r = s_p->targetEnvCall( QStringList{ "chown", it.perm.username(), bare_dest } );
if ( r )
cWarning() << "Could not chown target" << bare_dest;
r = s_p->targetEnvCall( QStringList{ "chgrp", it.perm.group(), bare_dest } );
if ( r )
cWarning() << "Could not chgrp target" << bare_dest;
r = s_p->targetEnvCall( QStringList{ "chmod", it.perm.octal(), bare_dest } );
if ( r )
cWarning() << "Could not chmod target" << bare_dest;
}
++count;
}
QFile destf( dest );
if ( !destf.open( QFile::WriteOnly ) )
{
sourcef.close();
cWarning() << "Could not open" << destf.fileName() << "for writing; could not copy" << source;
continue;
}
QByteArray b;
do
{
b = sourcef.read( 1_MiB );
destf.write( b );
}
while ( b.count() > 0 );
sourcef.close();
destf.close();
++count;
}
}
@ -160,6 +192,10 @@ void PreserveFiles::setConfigurationMap(const QVariantMap& configurationMap)
return;
}
QString defaultPermissions = configurationMap[ "perm" ].toString();
if ( defaultPermissions.isEmpty() )
defaultPermissions = QStringLiteral( "root:root:0400" );
QVariantList l = files.toList();
unsigned int c = 0;
for ( const auto& li : l )
@ -168,7 +204,7 @@ void PreserveFiles::setConfigurationMap(const QVariantMap& configurationMap)
{
QString filename = li.toString();
if ( !filename.isEmpty() )
m_items.append( Item{ filename, filename, ItemType::Path } );
m_items.append( Item{ filename, filename, Permissions( defaultPermissions ), ItemType::Path } );
else
cDebug() << "Empty filename for preservefiles, item" << c;
}
@ -181,6 +217,9 @@ void PreserveFiles::setConfigurationMap(const QVariantMap& configurationMap)
( from == "log" ) ? ItemType::Log :
( from == "config" ) ? ItemType::Config :
ItemType::None;
QString perm = map[ "perm" ].toString();
if ( perm.isEmpty() )
perm = defaultPermissions;
if ( dest.isEmpty() )
{
@ -192,7 +231,7 @@ void PreserveFiles::setConfigurationMap(const QVariantMap& configurationMap)
}
else
{
m_items.append( Item{ QString(), dest, t } );
m_items.append( Item{ QString(), dest, Permissions( perm ), t } );
}
}
else

View File

@ -24,11 +24,11 @@
#include <QVariantMap>
#include "CppJob.h"
#include "PluginDllMacro.h"
#include "utils/PluginFactory.h"
#include "PluginDllMacro.h"
#include "permissions.h"
class PLUGINDLLEXPORT PreserveFiles : public Calamares::CppJob
{
@ -46,6 +46,7 @@ class PLUGINDLLEXPORT PreserveFiles : public Calamares::CppJob
{
QString source;
QString dest;
Permissions perm;
ItemType type;
} ;

View File

@ -0,0 +1,75 @@
/* === This file is part of Calamares - <https://github.com/calamares> ===
*
* Copyright (C) 2018 Scott Harvey <scott@spharvey.me>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include <QString>
#include <QStringList>
#include "permissions.h"
Permissions::Permissions() :
m_username(),
m_group(),
m_valid(false),
m_value(0)
{
}
Permissions::Permissions(QString p) : Permissions()
{
parsePermissions(p);
}
void Permissions::parsePermissions(const QString& p) {
QStringList segments = p.split(":");
if (segments.length() != 3) {
m_valid = false;
return;
}
if (segments[0].isEmpty() || segments[1].isEmpty()) {
m_valid = false;
return;
}
bool ok;
int octal = segments[2].toInt(&ok, 8);
if (!ok || octal == 0) {
m_valid = false;
return;
} else {
m_value = octal;
}
// We have exactly three segments and the third is valid octal,
// so we can declare the string valid and set the user and group names
m_valid = true;
m_username = segments[0];
m_group = segments[1];
return;
}

View File

@ -0,0 +1,62 @@
/* === This file is part of Calamares - <https://github.com/calamares> ===
*
* Copyright (C) 2018 Scott Harvey <scott@spharvey.me>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef PERMISSIONS_H
#define PERMISSIONS_H
#include <QString>
/**
* @brief The Permissions class takes a QString @p in the form of
* <user>:<group>:<permissions>, checks it for validity, and makes the three
* components available indivdually.
*/
class Permissions
{
public:
/** @brief Constructor
*
* Splits the string @p at the colon (":") into separate elements for
* <user>, <group>, and <value> (permissions), where <value> is returned as
* an **octal** integer.
*/
Permissions(QString p);
/** @brief Default constructor of an invalid Permissions. */
Permissions();
bool isValid() const { return m_valid; }
QString username() const { return m_username; }
QString group() const { return m_group; }
int value() const { return m_value; }
QString octal() const { return QString::number( m_value, 8 ); }
private:
void parsePermissions(QString const &p);
QString m_username;
QString m_group;
bool m_valid;
int m_value;
};
#endif // PERMISSIONS_H

View File

@ -9,13 +9,18 @@
# as the source).
# - a map with a *dest* key. The *dest* value is a path interpreted in the
# target system (if dontChroot is true, in the host system). Relative paths
# are not recommended. There are two possible other keys in the map:
# are not recommended. There are three possible other keys in the map:
# - *from*, which must have one of the values, below; it is used to
# preserve files whose pathname is known to Calamares internally.
# - *src*, to refer to a path interpreted in the host system. Relative
# paths are not recommended, and are interpreted relative to where
# Calamares is being run.
# Only one of the two other keys (either *from* or *src*) may be set.
# - *perm*, is a colon-separated tuple of <user>:<group>:<mode>
# where <mode> is in octal (e.g. 4777 for wide-open, 0400 for read-only
# by owner). If set, the file's ownership and permissions are set to
# those values within the target system; if not set, no permissions
# are changed.
# Only one of the two source keys (either *from* or *src*) may be set.
#
# The target filename is modified as follows:
# - `@@ROOT@@` is replaced by the path to the target root (may be /)
@ -32,5 +37,13 @@ files:
- /etc/oem-information
- from: log
dest: /root/install.log
perm: root:wheel:644
- from: config
dest: /root/install.cfg
perm: root:wheel:400
# 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,
# root:root:0400 (highly restrictive) is used.
#
# perm: "root:root:0400"

View File

@ -8,10 +8,7 @@ calamares_add_plugin( shellprocess
SHARED_LIB
)
if( ECM_FOUND )
find_package( Qt5 COMPONENTS Test REQUIRED )
include( ECMAddTests )
if( ECM_FOUND AND BUILD_TESTING )
ecm_add_test(
Tests.cpp
TEST_NAME

View File

@ -87,7 +87,7 @@ int main(int argc, char** argv)
if ( !doc.IsMap() )
{
cerr << "WARNING:" << filename << '\n';
cerr << "WARNING: not-a-YAML-map\n";
cerr << "WARNING: not-a-YAML-map (type=" << doc.Type() << ")\n";
return 1;
}

View File

@ -1,9 +1,4 @@
find_package(ECM ${ECM_VERSION} NO_MODULE)
if( ECM_FOUND )
include( ECMAddTests )
endif()
find_package( Qt5 COMPONENTS Core Test REQUIRED )
find_package( Qt5 COMPONENTS Core REQUIRED )
find_package( Crypt REQUIRED )
# Add optional libraries here
@ -44,7 +39,7 @@ calamares_add_plugin( users
SHARED_LIB
)
if( ECM_FOUND )
if( ECM_FOUND AND BUILD_TESTING )
ecm_add_test(
PasswordTests.cpp
SetPasswordJob.cpp