[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): This release contains contributions from (alphabetically by first name):
- Alf Gaida - Alf Gaida
- Caio Carvalho - Caio Carvalho
- Kevin Kofler
- Philip Mueller - Philip Mueller
- Scott Harvey
## Core ## ## 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 ## ## Modules ##
* The *partition* module supports RAID devices, but only when Calamares * The *partition* module supports RAID devices, but only when Calamares
is compiled with the newest KPMCore release. 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) # # 3.2.2 (2018-09-04) #

View File

@ -237,6 +237,11 @@ set_package_properties(
find_package(ECM ${ECM_VERSION} NO_MODULE) find_package(ECM ${ECM_VERSION} NO_MODULE)
if( ECM_FOUND ) if( ECM_FOUND )
set(CMAKE_MODULE_PATH ${ECM_MODULE_PATH} ${CMAKE_MODULE_PATH}) 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() endif()
find_package( KF5 COMPONENTS CoreAddons Crash ) find_package( KF5 COMPONENTS CoreAddons Crash )

View File

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

View File

@ -51,4 +51,4 @@ df -h
echo "# Install results" echo "# Install results"
install_debugging "$DESTDIR" 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> <message>
<location filename="../src/modules/partition/gui/PartitionPage.cpp" line="196"/> <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> <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> </message>
</context> </context>
<context> <context>

View File

@ -4,7 +4,7 @@
<message> <message>
<location filename="../src/modules/partition/gui/BootInfoWidget.cpp" line="69"/> <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> <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>
<message> <message>
<location filename="../src/modules/partition/gui/BootInfoWidget.cpp" line="79"/> <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> <message>
<location filename="../src/modules/contextualprocess/ContextualProcessJob.cpp" line="117"/> <location filename="../src/modules/contextualprocess/ContextualProcessJob.cpp" line="117"/>
<source>Contextual Processes Job</source> <source>Contextual Processes Job</source>
<translation type="unfinished"/> <translation>משימת תהליכי הקשר</translation>
</message> </message>
</context> </context>
<context> <context>
@ -2358,7 +2358,7 @@ Output:
<message> <message>
<location filename="../src/modules/shellprocess/ShellProcessJob.cpp" line="51"/> <location filename="../src/modules/shellprocess/ShellProcessJob.cpp" line="51"/>
<source>Shell Processes Job</source> <source>Shell Processes Job</source>
<translation type="unfinished"/> <translation>משימת תהליכי מעטפת</translation>
</message> </message>
</context> </context>
<context> <context>

View File

@ -207,7 +207,7 @@
<message> <message>
<location filename="../src/libcalamaresui/ViewManager.cpp" line="277"/> <location filename="../src/libcalamaresui/ViewManager.cpp" line="277"/>
<source>&amp;Install</source> <source>&amp;Install</source>
<translation type="unfinished"/> <translation>&amp;Telepítés</translation>
</message> </message>
<message> <message>
<location filename="../src/libcalamaresui/ViewManager.cpp" line="325"/> <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> <message>
<location filename="../src/libcalamaresui/ViewManager.cpp" line="332"/> <location filename="../src/libcalamaresui/ViewManager.cpp" line="332"/>
<source>&amp;No</source> <source>&amp;No</source>
<translation>@Nem</translation> <translation>&amp;Nem</translation>
</message> </message>
<message> <message>
<location filename="../src/libcalamaresui/ViewManager.cpp" line="163"/> <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> <message>
<location filename="../src/modules/finished/FinishedPage.ui" line="98"/> <location filename="../src/modules/finished/FinishedPage.ui" line="98"/>
<source>&amp;Restart now</source> <source>&amp;Restart now</source>
<translation>jraindítás most</translation> <translation>Új&amp;raindítás most</translation>
</message> </message>
<message> <message>
<location filename="../src/modules/finished/FinishedPage.cpp" line="51"/> <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> <message>
<location filename="../src/libcalamaresui/ViewManager.cpp" line="238"/> <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> <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>
<message> <message>
<location filename="../src/libcalamaresui/ViewManager.cpp" line="243"/> <location filename="../src/libcalamaresui/ViewManager.cpp" line="243"/>

View File

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

View File

@ -9,7 +9,7 @@
<message> <message>
<location filename="../src/modules/partition/gui/BootInfoWidget.cpp" line="79"/> <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> <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>
<message> <message>
<location filename="../src/modules/partition/gui/BootInfoWidget.cpp" line="91"/> <location filename="../src/modules/partition/gui/BootInfoWidget.cpp" line="91"/>
@ -51,7 +51,7 @@
<message> <message>
<location filename="../src/libcalamaresui/viewpages/BlankViewStep.cpp" line="69"/> <location filename="../src/libcalamaresui/viewpages/BlankViewStep.cpp" line="69"/>
<source>Blank Page</source> <source>Blank Page</source>
<translation type="unfinished"/> <translation></translation>
</message> </message>
</context> </context>
<context> <context>
@ -193,17 +193,17 @@
<message> <message>
<location filename="../src/libcalamaresui/ViewManager.cpp" line="179"/> <location filename="../src/libcalamaresui/ViewManager.cpp" line="179"/>
<source>Calamares Initialization Failed</source> <source>Calamares Initialization Failed</source>
<translation type="unfinished"/> <translation>Calamares安装失败</translation>
</message> </message>
<message> <message>
<location filename="../src/libcalamaresui/ViewManager.cpp" line="180"/> <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> <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>
<message> <message>
<location filename="../src/libcalamaresui/ViewManager.cpp" line="185"/> <location filename="../src/libcalamaresui/ViewManager.cpp" line="185"/>
<source>&lt;br/&gt;The following modules could not be loaded:</source> <source>&lt;br/&gt;The following modules could not be loaded:</source>
<translation type="unfinished"/> <translation>&lt;br/&gt;</translation>
</message> </message>
<message> <message>
<location filename="../src/libcalamaresui/ViewManager.cpp" line="277"/> <location filename="../src/libcalamaresui/ViewManager.cpp" line="277"/>
@ -265,7 +265,7 @@ The installer will quit and all changes will be lost.</source>
<message> <message>
<location filename="../src/libcalamaresui/ViewManager.cpp" line="284"/> <location filename="../src/libcalamaresui/ViewManager.cpp" line="284"/>
<source>The installation is complete. Close the installer.</source> <source>The installation is complete. Close the installer.</source>
<translation></translation> <translation></translation>
</message> </message>
<message> <message>
<location filename="../src/libcalamaresui/ViewManager.cpp" line="160"/> <location filename="../src/libcalamaresui/ViewManager.cpp" line="160"/>
@ -334,7 +334,7 @@ The installer will quit and all changes will be lost.</source>
<message> <message>
<location filename="../src/modules/welcome/checker/CheckerWidget.cpp" line="174"/> <location filename="../src/modules/welcome/checker/CheckerWidget.cpp" line="174"/>
<source>For best results, please ensure that this computer:</source> <source>For best results, please ensure that this computer:</source>
<translation>: </translation> <translation>: </translation>
</message> </message>
<message> <message>
<location filename="../src/modules/welcome/checker/CheckerWidget.cpp" line="202"/> <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> <message>
<location filename="../src/libcalamares/utils/CommandList.cpp" line="128"/> <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> <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>
<message> <message>
<location filename="../src/libcalamares/utils/CommandList.cpp" line="139"/> <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> <source>The command needs to know the user&apos;s name, but no username is defined.</source>
<translation type="unfinished"/> <translation></translation>
</message> </message>
</context> </context>
<context> <context>
@ -1665,7 +1665,7 @@ The installer will quit and all changes will be lost.</source>
<message> <message>
<location filename="../src/modules/partition/gui/PartitionPage.ui" line="107"/> <location filename="../src/modules/partition/gui/PartitionPage.ui" line="107"/>
<source>Cre&amp;ate</source> <source>Cre&amp;ate</source>
<translation type="unfinished"/> <translation></translation>
</message> </message>
<message> <message>
<location filename="../src/modules/partition/gui/PartitionPage.ui" line="114"/> <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> <message>
<location filename="../src/modules/partition/gui/PartitionPage.cpp" line="195"/> <location filename="../src/modules/partition/gui/PartitionPage.cpp" line="195"/>
<source>Can not create new partition</source> <source>Can not create new partition</source>
<translation type="unfinished"/> <translation></translation>
</message> </message>
<message> <message>
<location filename="../src/modules/partition/gui/PartitionPage.cpp" line="196"/> <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> <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> </message>
</context> </context>
<context> <context>
@ -1841,17 +1841,17 @@ The installer will quit and all changes will be lost.</source>
<message> <message>
<location filename="../src/modules/preservefiles/PreserveFiles.cpp" line="83"/> <location filename="../src/modules/preservefiles/PreserveFiles.cpp" line="83"/>
<source>Saving files for later ...</source> <source>Saving files for later ...</source>
<translation type="unfinished"/> <translation>使</translation>
</message> </message>
<message> <message>
<location filename="../src/modules/preservefiles/PreserveFiles.cpp" line="89"/> <location filename="../src/modules/preservefiles/PreserveFiles.cpp" line="89"/>
<source>No files configured to save for later.</source> <source>No files configured to save for later.</source>
<translation type="unfinished"/> <translation>使</translation>
</message> </message>
<message> <message>
<location filename="../src/modules/preservefiles/PreserveFiles.cpp" line="145"/> <location filename="../src/modules/preservefiles/PreserveFiles.cpp" line="145"/>
<source>Not all of the configured files could be preserved.</source> <source>Not all of the configured files could be preserved.</source>
<translation type="unfinished"/> <translation></translation>
</message> </message>
</context> </context>
<context> <context>

Binary file not shown.

View File

@ -10,7 +10,7 @@ msgstr ""
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2018-06-18 07:46-0400\n" "POT-Creation-Date: 2018-06-18 07:46-0400\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\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" "Language-Team: Hungarian (https://www.transifex.com/calamares/teams/20061/hu/)\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"
@ -20,7 +20,7 @@ msgstr ""
#: src/modules/umount/main.py:40 #: src/modules/umount/main.py:40
msgid "Unmount file systems." msgid "Unmount file systems."
msgstr "" msgstr "Fájlrendszerek leválasztása."
#: src/modules/dummypython/main.py:44 #: src/modules/dummypython/main.py:44
msgid "Dummy python job." msgid "Dummy python job."
@ -47,12 +47,12 @@ msgstr "Csomagok telepítése."
#, python-format #, python-format
msgid "Installing one package." msgid "Installing one package."
msgid_plural "Installing %(num)d packages." msgid_plural "Installing %(num)d packages."
msgstr[0] "" msgstr[0] "Egy csomag telepítése."
msgstr[1] "" msgstr[1] "%(num)d csomag telepítése."
#: src/modules/packages/main.py:70 #: src/modules/packages/main.py:70
#, python-format #, python-format
msgid "Removing one package." msgid "Removing one package."
msgid_plural "Removing %(num)d packages." msgid_plural "Removing %(num)d packages."
msgstr[0] "" msgstr[0] "Egy csomag eltávolítása."
msgstr[1] "" msgstr[1] "%(num)d csomag eltávolítása."

View File

@ -145,6 +145,9 @@ qmlDirCandidates( bool assumeBuilddir )
{ {
if ( assumeBuilddir ) if ( assumeBuilddir )
qmlDirs << QDir::current().absoluteFilePath( "src/qml" ); // In build-dir 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 ); qmlDirs << CalamaresUtils::appDataDir().absoluteFilePath( QML );
} }
@ -164,6 +167,9 @@ settingsFileCandidates( bool assumeBuilddir )
{ {
if ( assumeBuilddir ) if ( assumeBuilddir )
settingsPaths << QDir::current().absoluteFilePath( settings ); 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 << CMAKE_INSTALL_FULL_SYSCONFDIR "/calamares/settings.conf"; // String concat
settingsPaths << CalamaresUtils::appDataDir().absoluteFilePath( settings ); settingsPaths << CalamaresUtils::appDataDir().absoluteFilePath( settings );
} }
@ -182,6 +188,9 @@ brandingFileCandidates( bool assumeBuilddir, const QString& brandingFilename )
{ {
if ( assumeBuilddir ) if ( assumeBuilddir )
brandingPaths << ( QDir::currentPath() + QStringLiteral( "/src/" ) + brandingFilename ); 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 << QDir( CMAKE_INSTALL_FULL_SYSCONFDIR "/calamares/" ).absoluteFilePath( brandingFilename );
brandingPaths << CalamaresUtils::appDataDir().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" ); "Verbose output for debugging purposes (0-8).", "level" );
QCommandLineOption configOption( QStringList{ "c", "config"}, QCommandLineOption configOption( QStringList{ "c", "config"},
"Configuration directory to use, for testing purposes.", "config" ); "Configuration directory to use, for testing purposes.", "config" );
QCommandLineOption xdgOption( QStringList{"X", "xdg-config"},
"Use XDG_{CONFIG,DATA}_DIRS as well." );
QCommandLineParser parser; QCommandLineParser parser;
parser.setApplicationDescription( "Distribution-independent installer framework" ); parser.setApplicationDescription( "Distribution-independent installer framework" );
@ -53,6 +55,7 @@ handle_args( CalamaresApplication& a )
parser.addOption( debugOption ); parser.addOption( debugOption );
parser.addOption( debugLevelOption ); parser.addOption( debugLevelOption );
parser.addOption( configOption ); parser.addOption( configOption );
parser.addOption( xdgOption );
parser.process( a ); parser.process( a );
@ -72,6 +75,8 @@ handle_args( CalamaresApplication& a )
} }
if ( parser.isSet( configOption ) ) if ( parser.isSet( configOption ) )
CalamaresUtils::setAppDataDir( QDir( parser.value( configOption ) ) ); CalamaresUtils::setAppDataDir( QDir( parser.value( configOption ) ) );
if ( parser.isSet( xdgOption ) )
CalamaresUtils::setXdgDirs();
} }
int int

View File

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

View File

@ -105,6 +105,19 @@ install( TARGETS calamares
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} 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 # Make symlink lib/calamares/libcalamares.so to lib/libcalamares.so.VERSION so
# lib/calamares can be used as module path for the Python interpreter. # lib/calamares can be used as module path for the Python interpreter.
install( CODE " 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 QTranslator* s_translator = nullptr;
static QString s_translatorLocaleName; static QString s_translatorLocaleName;
static bool s_haveExtraDirs = false;
static QStringList s_extraConfigDirs;
static QStringList s_extraDataDirs;
static bool static bool
isWritableDir( const QDir& dir ) isWritableDir( const QDir& dir )
@ -94,6 +97,46 @@ setAppDataDir( const QDir& dir )
s_isAppDataDirOverridden = true; 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 bool
isAppDataDirOverridden() isAppDataDirOverridden()

View File

@ -79,6 +79,16 @@ namespace CalamaresUtils
DLLEXPORT void setQmlModulesDir( const QDir& dir ); 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 * @brief removeDiacritics replaces letters with diacritics and ligatures with
* alternative forms and digraphs. * alternative forms and digraphs.

View File

@ -55,6 +55,18 @@ setupLogLevel(unsigned int level)
s_threshold = level + 1; // Comparison is < in log() function 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 static void
log( const char* msg, unsigned int debugLevel, bool toDisk = true ) log( const char* msg, unsigned int debugLevel, bool toDisk = true )
{ {

View File

@ -89,6 +89,12 @@ namespace Logger
*/ */
DLLEXPORT void setupLogLevel( unsigned int level ); 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. * @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 ) ); paths << CalamaresUtils::appDataDir().absoluteFilePath( QString( "modules/%1" ).arg( configFileName ) );
else 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 ) if ( assumeBuildDir )
paths << QDir().absoluteFilePath(QString( "src/modules/%1/%2" ).arg( moduleName ).arg( configFileName ) ); 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 << QString( "/etc/calamares/modules/%1" ).arg( configFileName );
paths << CalamaresUtils::appDataDir().absoluteFilePath( QString( "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() ); YAML::Node doc = YAML::Load( ba.constData() );
if ( doc.IsNull() ) if ( doc.IsNull() )
{ {
cDebug() << "Found empty module configuration" << path;
// Special case: empty config files are valid, // Special case: empty config files are valid,
// but aren't a map. // but aren't a map.
return; return;
@ -178,14 +190,13 @@ Module::loadConfigurationFile( const QString& configFileName ) //throws YAML::Ex
return; return;
} }
cDebug() << "Loaded module configuration" << path;
m_configurationMap = CalamaresUtils::yamlMapToVariant( doc ).toMap(); m_configurationMap = CalamaresUtils::yamlMapToVariant( doc ).toMap();
m_emergency = m_maybe_emergency m_emergency = m_maybe_emergency
&& m_configurationMap.contains( EMERGENCY ) && m_configurationMap.contains( EMERGENCY )
&& m_configurationMap[ EMERGENCY ].toBool(); && m_configurationMap[ EMERGENCY ].toBool();
return; return;
} }
else
continue;
} }
} }

View File

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

View File

@ -8,9 +8,9 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: PACKAGE VERSION\n" "Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 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" "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" "Language-Team: Chinese (China) (https://www.transifex.com/calamares/teams/20061/zh_CN/)\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 +24,7 @@ msgstr "按我按我!"
#: src/modules/dummypythonqt/main.py:94 #: src/modules/dummypythonqt/main.py:94
msgid "A new QLabel." msgid "A new QLabel."
msgstr "一个平淡无奇的 QLabel。" msgstr "一个新的QLabel。"
#: src/modules/dummypythonqt/main.py:97 #: src/modules/dummypythonqt/main.py:97
msgid "Dummy PythonQt ViewStep" 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 QString
SetKeyboardLayoutJob::findConvertedKeymap( const QString& convertedKeymapPath ) const SetKeyboardLayoutJob::findConvertedKeymap( const QString& convertedKeymapPath ) const
{ {
cDebug() << "Looking for converted keymap in" << convertedKeymapPath;
// No search path supplied, assume the distribution does not provide // No search path supplied, assume the distribution does not provide
// converted keymaps // converted keymaps
if ( convertedKeymapPath.isEmpty() ) if ( convertedKeymapPath.isEmpty() )
@ -76,8 +78,7 @@ SetKeyboardLayoutJob::findConvertedKeymap( const QString& convertedKeymapPath )
if ( convertedKeymapDir.exists( name + ".map" ) if ( convertedKeymapDir.exists( name + ".map" )
|| convertedKeymapDir.exists( name + ".map.gz" ) ) || convertedKeymapDir.exists( name + ".map.gz" ) )
{ {
cDebug() << "Found converted keymap" << name; cDebug() << ".. Found converted keymap" << name;
return name; return name;
} }
@ -88,6 +89,8 @@ SetKeyboardLayoutJob::findConvertedKeymap( const QString& convertedKeymapPath )
QString QString
SetKeyboardLayoutJob::findLegacyKeymap() const SetKeyboardLayoutJob::findLegacyKeymap() const
{ {
cDebug() << "Looking for legacy keymap in QRC";
int bestMatching = 0; int bestMatching = 0;
QString name; QString name;
@ -137,7 +140,7 @@ SetKeyboardLayoutJob::findLegacyKeymap() const
// The best matching entry so far, then let's save that // The best matching entry so far, then let's save that
if ( matching >= qMax( bestMatching, 1 ) ) if ( matching >= qMax( bestMatching, 1 ) )
{ {
cDebug() << "Found legacy keymap" << mapping[0] cDebug() << ".. Found legacy keymap" << mapping[0]
<< "with score" << matching; << "with score" << matching;
if ( matching > bestMatching ) if ( matching > bestMatching )

View File

@ -6,6 +6,9 @@
# This is the version from 534644b7be7b240eb0fbbe06e20cbecbe8206767, # This is the version from 534644b7be7b240eb0fbbe06e20cbecbe8206767,
# committed 2015-01-22 01:07:24 . # 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 # Generated from system-config-keyboard's model list
# consolelayout xlayout xmodel xvariant xoptions # consolelayout xlayout xmodel xvariant xoptions
sg ch pc105 de_nodeadkeys terminate:ctrl_alt_bksp 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 trq tr pc105 - terminate:ctrl_alt_bksp
uk gb pc105 - terminate:ctrl_alt_bksp uk gb pc105 - terminate:ctrl_alt_bksp
is-latin1 is 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 de pc105 - terminate:ctrl_alt_bksp
de at pc105 - terminate:ctrl_alt_bksp
la-latin1 latam pc105 - terminate:ctrl_alt_bksp la-latin1 latam pc105 - terminate:ctrl_alt_bksp
us us pc105+inet - terminate:ctrl_alt_bksp us us pc105+inet - terminate:ctrl_alt_bksp
ko kr pc105 - 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 # When debugging the timezone widget, add this debugging definition
# to have a debugging-friendly timezone widget, debug logging, # to have a debugging-friendly timezone widget, debug logging,
# and no intrusive timezone-setting while clicking around. # and no intrusive timezone-setting while clicking around.

View File

@ -134,7 +134,7 @@ def run():
if os.path.exists(target_locale_gen_bak): if os.path.exists(target_locale_gen_bak):
shutil.copy2(target_locale_gen_bak, target_locale_gen) shutil.copy2(target_locale_gen_bak, target_locale_gen)
libcalamares.utils.debug("Restored backup {!s} -> {!s}" 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 # run locale-gen if detected; this *will* cause an exception
# if the live system has locale.gen, but the target does not: # 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 // Remove the device which contains / from the list
for ( DeviceList::iterator it = devices.begin(); it != devices.end(); ) for ( DeviceList::iterator it = devices.begin(); it != devices.end(); )
if ( ! ( *it ) || if ( !( *it ) )
( *it )->deviceNode().startsWith( "/dev/zram" ) {
cDebug() << " .. Skipping nullptr device";
it = erase( devices, it);
}
else if ( ( *it )->deviceNode().startsWith( "/dev/zram" )
) )
{ {
cDebug() << " .. Removing zram" << it; cDebug() << " .. Removing zram" << it;
it = erase(devices, it ); it = erase( devices, it );
} }
else if ( writableOnly && hasRootPartition( *it ) ) else if ( writableOnly && hasRootPartition( *it ) )
{ {
cDebug() << " .. Removing device with root filesystem (/) on it" << it; cDebug() << " .. Removing device with root filesystem (/) on it" << it;
it = erase(devices, it ); it = erase( devices, it );
} }
else if ( writableOnly && isIso9660( *it ) ) else if ( writableOnly && isIso9660( *it ) )
{ {
cDebug() << " .. Removing device with iso9660 filesystem (probably a CD) on it" << 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 ) ) else if ( (minimumSize >= 0) && !( (*it)->capacity() > minimumSize ) )
{ {
cDebug() << " .. Removing too-small" << it; cDebug() << " .. Removing too-small" << it;
it = erase(devices, it ); it = erase( devices, it );
} }
else else
++it; ++it;

View File

@ -509,18 +509,8 @@ PartitionCoreModule::jobs() const
lst << info->jobs; lst << info->jobs;
devices << info->device.data(); devices << info->device.data();
} }
cDebug() << "Creating FillGlobalStorageJob with bootLoader path" << m_bootLoaderInstallPath;
lst << Calamares::job_ptr( new FillGlobalStorageJob( devices, 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; return lst;
} }
@ -573,9 +563,9 @@ PartitionCoreModule::dumpQueue() const
cDebug() << "# Queue:"; cDebug() << "# Queue:";
for ( auto info : m_deviceInfos ) for ( auto info : m_deviceInfos )
{ {
cDebug() << " .. Device:" << info->device->name(); cDebug() << "## Device:" << info->device->name();
for ( auto job : info->jobs ) 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/>. * along with Calamares. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include <core/PartitionIterator.h> #include "PartitionIterator.h"
// KPMcore // KPMcore
#include <kpmcore/core/device.h> #include <kpmcore/core/device.h>

View File

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

View File

@ -20,6 +20,8 @@
#include "jobs/CreatePartitionTableJob.h" #include "jobs/CreatePartitionTableJob.h"
#include "core/PartitionIterator.h"
#include "utils/Logger.h" #include "utils/Logger.h"
// KPMcore // 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 Calamares::JobResult
CreatePartitionTableJob::exec() CreatePartitionTableJob::exec()
{ {
@ -73,33 +83,28 @@ CreatePartitionTableJob::exec()
PartitionTable* table = m_device->partitionTable(); PartitionTable* table = m_device->partitionTable();
cDebug() << "Creating new partition table of type" << table->typeName() cDebug() << "Creating new partition table of type" << table->typeName()
<< " - Uncommitted yet: " << table; << ", uncommitted yet:";
QProcess lsblk; if ( Logger::logLevelEnabled( Logger::LOGDEBUG ) )
lsblk.setProgram( "lsblk" ); {
lsblk.setProcessChannelMode( QProcess::MergedChannels ); for ( auto it = PartitionIterator::begin( table );
lsblk.start(); it != PartitionIterator::end( table ); ++it )
lsblk.waitForFinished(); cDebug() << *it;
QByteArray byte = lsblk.readAllStandardOutput(); QProcess lsblk;
QStringList lines = QString(byte).split(("\n"),QString::SkipEmptyParts); lsblk.setProgram( "lsblk" );
cDebug() << "CreatePartitionTableJob asked for lsblk output:"; lsblk.setProcessChannelMode( QProcess::MergedChannels );
lsblk.start();
lsblk.waitForFinished();
cDebug() << "lsblk:\n" << lsblk.readAllStandardOutput();
for (const auto line: lines) QProcess mount;
cDebug() << " .." << line; mount.setProgram( "mount" );
mount.setProcessChannelMode( QProcess::MergedChannels );
QProcess mount; mount.start();
mount.setProgram( "mount" ); mount.waitForFinished();
mount.setProcessChannelMode( QProcess::MergedChannels ); cDebug() << "mount:\n" << mount.readAllStandardOutput();
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;
CreatePartitionTableOperation op(*m_device, table); CreatePartitionTableOperation op(*m_device, table);
op.setStatus(Operation::StatusRunning); op.setStatus(Operation::StatusRunning);

View File

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

View File

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

View File

@ -1,6 +1,4 @@
find_package( Qt5 COMPONENTS Gui Test REQUIRED ) find_package( Qt5 COMPONENTS Gui REQUIRED )
include( ECMAddTests )
set( PartitionModule_SOURCE_DIR .. ) set( PartitionModule_SOURCE_DIR .. )
@ -23,13 +21,15 @@ include_directories(
${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_BINARY_DIR}
) )
ecm_add_test( ${partitionjobtests_SRCS} if( ECM_FOUND AND BUILD_TESTING )
TEST_NAME partitionjobtests ecm_add_test( ${partitionjobtests_SRCS}
LINK_LIBRARIES TEST_NAME partitionjobtests
${CALAMARES_LIBRARIES} LINK_LIBRARIES
kpmcore ${CALAMARES_LIBRARIES}
Qt5::Core kpmcore
Qt5::Test 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 TYPE job
EXPORT_MACRO PLUGINDLLEXPORT_PRO EXPORT_MACRO PLUGINDLLEXPORT_PRO
SOURCES SOURCES
permissions.cpp
PreserveFiles.cpp PreserveFiles.cpp
LINK_PRIVATE_LIBRARIES LINK_PRIVATE_LIBRARIES
calamares calamares

View File

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

View File

@ -24,11 +24,11 @@
#include <QVariantMap> #include <QVariantMap>
#include "CppJob.h" #include "CppJob.h"
#include "PluginDllMacro.h"
#include "utils/PluginFactory.h" #include "utils/PluginFactory.h"
#include "PluginDllMacro.h" #include "permissions.h"
class PLUGINDLLEXPORT PreserveFiles : public Calamares::CppJob class PLUGINDLLEXPORT PreserveFiles : public Calamares::CppJob
{ {
@ -46,6 +46,7 @@ class PLUGINDLLEXPORT PreserveFiles : public Calamares::CppJob
{ {
QString source; QString source;
QString dest; QString dest;
Permissions perm;
ItemType type; 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). # 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 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 # - *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.
# 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: # The target filename 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 /)
@ -32,5 +37,13 @@ files:
- /etc/oem-information - /etc/oem-information
- from: log - from: log
dest: /root/install.log dest: /root/install.log
perm: root:wheel:644
- from: config - from: config
dest: /root/install.cfg 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 SHARED_LIB
) )
if( ECM_FOUND ) if( ECM_FOUND AND BUILD_TESTING )
find_package( Qt5 COMPONENTS Test REQUIRED )
include( ECMAddTests )
ecm_add_test( ecm_add_test(
Tests.cpp Tests.cpp
TEST_NAME TEST_NAME

View File

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

View File

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