diff --git a/CHANGES b/CHANGES
index 8c56b4023..7094f5866 100644
--- a/CHANGES
+++ b/CHANGES
@@ -8,14 +8,36 @@ website will have to do for older versions.
This release contains contributions from (alphabetically by first name):
- Alf Gaida
- Caio Carvalho
+ - Kevin Kofler
- Philip Mueller
+ - Scott Harvey
## Core ##
+ * The Calamares application now recognizes the `-X` or `--xdg-config`
+ option, which adds XDG_DATA_DIRS to the places used to find QML
+ and branding directories, and XDG_CONFIG_DIRS to the places used
+ to find the global settings and module configurations. This allows
+ a more fine-grained, and more layered, approach to setting up
+ Calamares configurations (in particular, distro's can **add**
+ configuration files and give them priority, instead of **forking**
+ configuration files).
+
## Modules ##
* The *partition* module supports RAID devices, but only when Calamares
is compiled with the newest KPMCore release.
+ * The calculation of required space -- including swap -- has been simplified,
+ and Calamares no longer reserves 2GiB of space in calculations for internal
+ use (this means that it no longer mysteriously drops swap when the disk
+ size is close to the required installation size).
+ * The *keyboard* module now handles the (bogus) Austrian keymap for
+ the system console properly.
+ * The *preservefiles* module now has a mechanism for setting the permissions
+ (and ownership) of preserved files.
+ * New module *fsresizer* can be used to resize filesystems. It is intended
+ for use in OEM installs where an image of fixed size is created,
+ and then sized to the actual SD card the user has used.
# 3.2.2 (2018-09-04) #
diff --git a/CMakeLists.txt b/CMakeLists.txt
index f241cedd0..4fb88420b 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -237,6 +237,11 @@ set_package_properties(
find_package(ECM ${ECM_VERSION} NO_MODULE)
if( ECM_FOUND )
set(CMAKE_MODULE_PATH ${ECM_MODULE_PATH} ${CMAKE_MODULE_PATH})
+ if ( BUILD_TESTING )
+ # ECM implies that we can build the tests, too
+ find_package( Qt5 COMPONENTS Test REQUIRED )
+ include( ECMAddTests )
+ endif()
endif()
find_package( KF5 COMPONENTS CoreAddons Crash )
diff --git a/calamares.desktop b/calamares.desktop
index 3cdce6888..46b2e979f 100644
--- a/calamares.desktop
+++ b/calamares.desktop
@@ -14,165 +14,165 @@ Categories=Qt;System;
X-AppStream-Ignore=true
Name[ar]=نظام التثبيت
-Icon[be]=calamares
-GenericName[be]=Усталёўшчык сістэмы
Comment[be]=Calamares — усталёўшчык сістэмы
+Icon[be]=calamares
Name[be]=Усталяваць сістэму
-Icon[bg]=calamares
-GenericName[bg]=Системен Инсталатор
+GenericName[be]=Усталёўшчык сістэмы
Comment[bg]=Calamares — Системен Инсталатор
+Icon[bg]=calamares
Name[bg]=Инсталирай системата
-Icon[ca]=calamares
-GenericName[ca]=Instal·lador de sistema
+GenericName[bg]=Системен Инсталатор
Comment[ca]=Calamares — Instal·lador de sistema
+Icon[ca]=calamares
Name[ca]=Instal·la el sistema
-Icon[da]=calamares
-GenericName[da]=Systeminstallationsprogram
+GenericName[ca]=Instal·lador de sistema
Comment[da]=Calamares — Systeminstallationsprogram
+Icon[da]=calamares
Name[da]=Installér system
-Icon[de]=calamares
-GenericName[de]=Installation des Betriebssystems
+GenericName[da]=Systeminstallationsprogram
Comment[de]=Calamares - Installation des Betriebssystems
+Icon[de]=calamares
Name[de]=System installieren
-Icon[el]=calamares
-GenericName[el]=Εγκατάσταση συστήματος
+GenericName[de]=Installation des Betriebssystems
Comment[el]=Calamares — Εγκατάσταση συστήματος
+Icon[el]=calamares
Name[el]=Εγκατάσταση συστήματος
-Icon[en_GB]=calamares
-GenericName[en_GB]=System Installer
+GenericName[el]=Εγκατάσταση συστήματος
Comment[en_GB]=Calamares — System Installer
+Icon[en_GB]=calamares
Name[en_GB]=Install System
-Icon[es]=calamares
-GenericName[es]=Instalador del Sistema
+GenericName[en_GB]=System Installer
Comment[es]=Calamares — Instalador del Sistema
+Icon[es]=calamares
Name[es]=Instalar Sistema
-Icon[et]=calamares
-GenericName[et]=Süsteemipaigaldaja
+GenericName[es]=Instalador del Sistema
Comment[et]=Calamares — süsteemipaigaldaja
+Icon[et]=calamares
Name[et]=Paigalda süsteem
+GenericName[et]=Süsteemipaigaldaja
Name[eu]=Sistema instalatu
Name[es_PR]=Instalar el sistema
-Icon[fr]=calamares
-GenericName[fr]=Installateur système
Comment[fr]=Calamares - Installateur système
+Icon[fr]=calamares
Name[fr]=Installer le système
+GenericName[fr]=Installateur système
Name[gl]=Instalación do Sistema
-Icon[he]=calamares
-GenericName[he]=אשף התקנה
Comment[he]=Calamares - אשף התקנה
+Icon[he]=calamares
Name[he]=התקנת מערכת
-Icon[hi]=calamares
-GenericName[hi]=सिस्टम इंस्टॉलर
+GenericName[he]=אשף התקנה
Comment[hi]=Calamares — सिस्टम इंस्टॉलर
+Icon[hi]=calamares
Name[hi]=सिस्टम इंस्टॉल करें
-Icon[hr]=calamares
-GenericName[hr]=Instalacija sustava
+GenericName[hi]=सिस्टम इंस्टॉलर
Comment[hr]=Calamares — Instalacija sustava
+Icon[hr]=calamares
Name[hr]=Instaliraj sustav
-Icon[hu]=calamares
-GenericName[hu]=Rendszer Telepítő
+GenericName[hr]=Instalacija sustava
Comment[hu]=Calamares — Rendszer Telepítő
+Icon[hu]=calamares
Name[hu]=Rendszer telepítése
-Icon[id]=calamares
-GenericName[id]=Pemasang
+GenericName[hu]=Rendszer Telepítő
Comment[id]=Calamares — Pemasang Sistem
+Icon[id]=calamares
Name[id]=Instal Sistem
-Icon[is]=calamares
-GenericName[is]=Kerfis uppsetning
+GenericName[id]=Pemasang
Comment[is]=Calamares — Kerfis uppsetning
+Icon[is]=calamares
Name[is]=Setja upp kerfið
-Icon[cs_CZ]=calamares
-GenericName[cs_CZ]=Instalátor systému
+GenericName[is]=Kerfis uppsetning
Comment[cs_CZ]=Calamares – instalátor operačních systémů
+Icon[cs_CZ]=calamares
Name[cs_CZ]=Nainstalovat
-Icon[ja]=calamares
-GenericName[ja]=システムインストーラー
+GenericName[cs_CZ]=Instalátor systému
Comment[ja]=Calamares — システムインストーラー
+Icon[ja]=calamares
Name[ja]=システムをインストール
-Icon[ko]=깔라마레스
-GenericName[ko]=시스템 설치 관리자
+GenericName[ja]=システムインストーラー
Comment[ko]=깔라마레스 — 시스템 설치 관리자
+Icon[ko]=깔라마레스
Name[ko]=시스템 설치
-Icon[lt]=calamares
-GenericName[lt]=Sistemos diegimas į kompiuterį
+GenericName[ko]=시스템 설치 관리자
Comment[lt]=Calamares — Sistemos diegimo programa
+Icon[lt]=calamares
Name[lt]=Įdiegti Sistemą
-Icon[it_IT]=calamares
-GenericName[it_IT]=Programma d'installazione del sistema
+GenericName[lt]=Sistemos diegimas į kompiuterį
Comment[it_IT]=Calamares — Programma d'installazione del sistema
+Icon[it_IT]=calamares
Name[it_IT]=Installa il sistema
-Icon[nb]=calamares
-GenericName[nb]=Systeminstallatør
+GenericName[it_IT]=Programma d'installazione del sistema
Comment[nb]=Calamares-systeminstallatør
+Icon[nb]=calamares
Name[nb]=Installer System
-Icon[nl]=calamares
-GenericName[nl]=Installatieprogramma
+GenericName[nb]=Systeminstallatør
Comment[nl]=Calamares — Installatieprogramma
+Icon[nl]=calamares
Name[nl]=Installeer systeem
-Icon[pl]=calamares
-GenericName[pl]=Instalator systemu
+GenericName[nl]=Installatieprogramma
Comment[pl]=Calamares — Instalator systemu
+Icon[pl]=calamares
Name[pl]=Zainstaluj system
-Icon[pt_BR]=calamares
-GenericName[pt_BR]=Instalador de Sistema
+GenericName[pl]=Instalator systemu
Comment[pt_BR]=Calamares — Instalador de Sistema
+Icon[pt_BR]=calamares
Name[pt_BR]=Sistema de Instalação
-Icon[ro]=calamares
-GenericName[ro]=Instalator de sistem
+GenericName[pt_BR]=Instalador de Sistema
Comment[ro]=Calamares — Instalator de sistem
+Icon[ro]=calamares
Name[ro]=Instalează sistemul
-Icon[ru]=calamares
-GenericName[ru]=Установщик системы
+GenericName[ro]=Instalator de sistem
Comment[ru]=Calamares - Установщик системы
+Icon[ru]=calamares
Name[ru]=Установить систему
-Icon[sk]=calamares
-GenericName[sk]=Inštalátor systému
+GenericName[ru]=Установщик системы
Comment[sk]=Calamares — Inštalátor systému
+Icon[sk]=calamares
Name[sk]=Inštalovať systém
+GenericName[sk]=Inštalátor systému
Name[sl]=Namesti sistem
-Icon[sq]=calamares
-GenericName[sq]=Instalues Sistemi
Comment[sq]=Calamares — Instalues Sistemi
+Icon[sq]=calamares
Name[sq]=Instalo Sistemin
-Icon[fi_FI]=calamares
-GenericName[fi_FI]=Järjestelmän Asennusohjelma
+GenericName[sq]=Instalues Sistemi
Comment[fi_FI]=Calamares — Järjestelmän Asentaja
+Icon[fi_FI]=calamares
Name[fi_FI]=Asenna Järjestelmä
+GenericName[fi_FI]=Järjestelmän Asennusohjelma
Name[sr@latin]=Instaliraj sistem
Name[sr]=Инсталирај систем
-Icon[sv]=calamares
-GenericName[sv]=Systeminstallerare
Comment[sv]=Calamares — Systeminstallerare
+Icon[sv]=calamares
Name[sv]=Installera system
+GenericName[sv]=Systeminstallerare
Name[th]=ติดตั้งระบบ
-GenericName[uk]=Встановлювач системи
Comment[uk]=Calamares - Встановлювач системи
Name[uk]=Встановити Систему
-Icon[zh_CN]=calamares
-GenericName[zh_CN]=系统安装程序
+GenericName[uk]=Встановлювач системи
Comment[zh_CN]=Calamares — 系统安装程序
+Icon[zh_CN]=calamares
Name[zh_CN]=安装系统
-Icon[zh_TW]=calamares
-GenericName[zh_TW]=系統安裝程式
+GenericName[zh_CN]=系统安装程序
Comment[zh_TW]=Calamares ── 系統安裝程式
+Icon[zh_TW]=calamares
Name[zh_TW]=安裝系統
-Icon[ast]=calamares
-GenericName[ast]=Instalador del sistema
+GenericName[zh_TW]=系統安裝程式
Comment[ast]=Calamares — Instalador del sistema
+Icon[ast]=calamares
Name[ast]=Instalar sistema
-Icon[eo]=calamares
-GenericName[eo]=Sistema Instalilo
+GenericName[ast]=Instalador del sistema
Comment[eo]=Calamares — Sistema Instalilo
+Icon[eo]=calamares
Name[eo]=Instali Sistemo
-Icon[es_MX]=calamares
-GenericName[es_MX]=Instalador del sistema
+GenericName[eo]=Sistema Instalilo
Comment[es_MX]=Calamares - Instalador del sistema
+Icon[es_MX]=calamares
Name[es_MX]=Instalar el Sistema
-Icon[pt_PT]=calamares
-GenericName[pt_PT]=Instalador de Sistema
+GenericName[es_MX]=Instalador del sistema
Comment[pt_PT]=Calamares - Instalador de Sistema
+Icon[pt_PT]=calamares
Name[pt_PT]=Instalar Sistema
-Icon[tr_TR]=calamares
-GenericName[tr_TR]=Sistem Yükleyici
+GenericName[pt_PT]=Instalador de Sistema
Comment[tr_TR]=Calamares — Sistem Yükleyici
+Icon[tr_TR]=calamares
Name[tr_TR]=Sistemi Yükle
+GenericName[tr_TR]=Sistem Yükleyici
diff --git a/ci/travis-continuous.sh b/ci/travis-continuous.sh
index eccb6743e..1b3841e54 100755
--- a/ci/travis-continuous.sh
+++ b/ci/travis-continuous.sh
@@ -51,4 +51,4 @@ df -h
echo "# Install results"
install_debugging "$DESTDIR"
-$result # Result of make install, above
+$result || { echo "! Install failed" ; exit 1 ; } # Result of make install, above
diff --git a/lang/calamares_da.ts b/lang/calamares_da.ts
index 7cfef1875..c69150583 100644
--- a/lang/calamares_da.ts
+++ b/lang/calamares_da.ts
@@ -1693,7 +1693,7 @@ Installationsprogrammet vil stoppe og alle ændringer vil gå tabt.
- Partitionstabellen på %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.
+ Partitionstabellen på %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.
diff --git a/lang/calamares_fr.ts b/lang/calamares_fr.ts
index 572a4b1df..26062f604 100644
--- a/lang/calamares_fr.ts
+++ b/lang/calamares_fr.ts
@@ -4,7 +4,7 @@
- L'<strong>environnement de démarrage</strong> de ce système.<br><br>Les anciens systèmes x86 supportent uniquement le <strong>BIOS</strong>.<br>Les systèmes récents utilisent habituellement <strong>EFI</strong>, mais peuvent également afficher BIOS s'ils sont démarrés en mode de compatibilité.
+ L'<strong>environnement de démarrage</strong> de ce système.<br><br>Les anciens systèmes x86 supportent uniquement <strong>BIOS</strong>.<br>Les systèmes récents utilisent habituellement <strong>EFI</strong>, mais peuvent également afficher BIOS s'ils sont démarrés en mode de compatibilité.
diff --git a/lang/calamares_he.ts b/lang/calamares_he.ts
index fed3a48f4..cdceb60de 100644
--- a/lang/calamares_he.ts
+++ b/lang/calamares_he.ts
@@ -521,7 +521,7 @@ The installer will quit and all changes will be lost.
-
+ משימת תהליכי הקשר
@@ -2358,7 +2358,7 @@ Output:
-
+ משימת תהליכי מעטפת
diff --git a/lang/calamares_hu.ts b/lang/calamares_hu.ts
index 20ffbb815..75f3457b8 100644
--- a/lang/calamares_hu.ts
+++ b/lang/calamares_hu.ts
@@ -207,7 +207,7 @@
-
+ &Telepítés
@@ -229,7 +229,7 @@ Minden változtatás elveszik, ha kilépsz a telepítőből.
- @Nem
+ &Nem
@@ -944,7 +944,7 @@ Telepítés nem folytatható. <a href="#details">Részletek...&l
- $Újraindítás most
+ Új&raindítás most
diff --git a/lang/calamares_lt.ts b/lang/calamares_lt.ts
index 12d53ba11..33191566b 100644
--- a/lang/calamares_lt.ts
+++ b/lang/calamares_lt.ts
@@ -244,7 +244,7 @@ Diegimo programa užbaigs darbą ir visi pakeitimai bus prarasti.
- %1 diegimo programa, siekdama įdiegti %2, ketina atlikti pakeitimus diske.<br/><strong>Šių pakeitimų atšaukti nebegalėsite.</strong>
+ %1 diegimo programa, siekdama įdiegti %2, ketina atlikti pakeitimus diske.<br/><strong>Šių pakeitimų nebegalėsite atšaukti.</strong>
diff --git a/lang/calamares_nl.ts b/lang/calamares_nl.ts
index d20d75630..d1c1a62cc 100644
--- a/lang/calamares_nl.ts
+++ b/lang/calamares_nl.ts
@@ -50,7 +50,7 @@
-
+ Lege pagina
@@ -192,7 +192,7 @@
-
+ Calamares Initialisatie mislukt
@@ -202,7 +202,7 @@
-
+ <br/>The volgende modules konden niet worden geladen:
@@ -1244,7 +1244,7 @@ Het installatieprogramma zal afsluiten en alle wijzigingen zullen verloren gaan.
-
+ Wachtwoord is te zwak
@@ -1259,12 +1259,12 @@ Het installatieprogramma zal afsluiten en alle wijzigingen zullen verloren gaan.
-
+ Het wachtwoord is hetzelfde als het oude wachtwoord
-
+ Het wachtwoord is een palindroom
@@ -1274,12 +1274,12 @@ Het installatieprogramma zal afsluiten en alle wijzigingen zullen verloren gaan.
-
+ Het wachtwoord lijkt te veel op het oude wachtwoord
-
+ Het wachtwoord bevat de gebruikersnaam op een of andere manier
diff --git a/lang/calamares_zh_CN.ts b/lang/calamares_zh_CN.ts
index 4889eabf1..b69c5f63c 100644
--- a/lang/calamares_zh_CN.ts
+++ b/lang/calamares_zh_CN.ts
@@ -9,7 +9,7 @@
- 这个系统从 <strong>EFI</strong> 引导环境启动。<br><br>目前市面上大多数的民用设备都使用 EFI,并同时与之使用 GPT 分区表。<br>要从 EFI 环境引导的话,本安装程序必须部署一个引导器(如 <strong>GRUB</strong> 或 <strong>systemd-boot</strong>)到 <strong>EFI 系统分区</strong>。这个步骤是自动的,除非您选择手动分区——此时您必须自行选择或创建。
+ 这个系统是从 <strong>EFI</strong> 引导环境启动的。<br><br>目前市面上大多数的民用设备都使用 EFI,并同时对硬盘使用 GPT 分区表分区。<br>您如果要从 EFI 环境引导这个系统的话,本安装程序必须安装一个引导器(如 <strong>GRUB</strong> 或 <strong>systemd-boot</strong>)到 <strong>EFI 分区</strong>。这个步骤将会由本安装程序自动执行,除非您选择自己创建分区——此时您必须选择让本安装程序自动创建EFI分区或您自己手动创建EFI分区。
@@ -51,7 +51,7 @@
-
+ 空白页
@@ -193,17 +193,17 @@
-
+ Calamares安装失败
-
+ %1无法安装。 Calamares无法加载所有已配置的模块。这是分配使用Calamares的方式的问题。
-
+ <br/>无法加载以下模块:
@@ -265,7 +265,7 @@ The installer will quit and all changes will be lost.
- 安装过程已完毕。请关闭安装器。
+ 安装已完成。请关闭安装程序。
@@ -334,7 +334,7 @@ The installer will quit and all changes will be lost.
- 为了更好的体验,请确定这台电脑:
+ 为了更好的体验,请确保这台电脑:
@@ -509,12 +509,12 @@ The installer will quit and all changes will be lost.
-
+ 该命令在主机环境中运行,且需要知道根路径,但没有定义root挂载点。
-
+ 命令行需要知道用户的名字,但用户名没有被设置
@@ -1665,7 +1665,7 @@ The installer will quit and all changes will be lost.
-
+ 创建
@@ -1690,12 +1690,12 @@ The installer will quit and all changes will be lost.
-
+ 无法创建新分区
-
+ %1上的分区表已经有%2个主分区,并且不能再添加。请删除一个主分区并添加扩展分区。
@@ -1841,17 +1841,17 @@ The installer will quit and all changes will be lost.
-
+ 保存文件以供日后使用
-
+ 没有已保存且供日后使用的配置文件。
-
+ 并不是所有配置文件都可以被保留
diff --git a/lang/python/hu/LC_MESSAGES/python.mo b/lang/python/hu/LC_MESSAGES/python.mo
index 94e29ac49..4cb87d96a 100644
Binary files a/lang/python/hu/LC_MESSAGES/python.mo and b/lang/python/hu/LC_MESSAGES/python.mo differ
diff --git a/lang/python/hu/LC_MESSAGES/python.po b/lang/python/hu/LC_MESSAGES/python.po
index 286e27b3b..e2b46349c 100644
--- a/lang/python/hu/LC_MESSAGES/python.po
+++ b/lang/python/hu/LC_MESSAGES/python.po
@@ -10,7 +10,7 @@ msgstr ""
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2018-06-18 07:46-0400\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
-"Last-Translator: miku84, 2017\n"
+"Last-Translator: Adriaan de Groot , 2018\n"
"Language-Team: Hungarian (https://www.transifex.com/calamares/teams/20061/hu/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
@@ -20,7 +20,7 @@ msgstr ""
#: src/modules/umount/main.py:40
msgid "Unmount file systems."
-msgstr ""
+msgstr "Fájlrendszerek leválasztása."
#: src/modules/dummypython/main.py:44
msgid "Dummy python job."
@@ -47,12 +47,12 @@ msgstr "Csomagok telepítése."
#, python-format
msgid "Installing one package."
msgid_plural "Installing %(num)d packages."
-msgstr[0] ""
-msgstr[1] ""
+msgstr[0] "Egy csomag telepítése."
+msgstr[1] "%(num)d csomag telepítése."
#: src/modules/packages/main.py:70
#, python-format
msgid "Removing one package."
msgid_plural "Removing %(num)d packages."
-msgstr[0] ""
-msgstr[1] ""
+msgstr[0] "Egy csomag eltávolítása."
+msgstr[1] "%(num)d csomag eltávolítása."
diff --git a/src/calamares/CalamaresApplication.cpp b/src/calamares/CalamaresApplication.cpp
index 018e2b677..0b715d6df 100644
--- a/src/calamares/CalamaresApplication.cpp
+++ b/src/calamares/CalamaresApplication.cpp
@@ -145,6 +145,9 @@ qmlDirCandidates( bool assumeBuilddir )
{
if ( assumeBuilddir )
qmlDirs << QDir::current().absoluteFilePath( "src/qml" ); // In build-dir
+ if ( CalamaresUtils::haveExtraDirs() )
+ for ( auto s : CalamaresUtils::extraDataDirs() )
+ qmlDirs << ( s + QML );
qmlDirs << CalamaresUtils::appDataDir().absoluteFilePath( QML );
}
@@ -164,6 +167,9 @@ settingsFileCandidates( bool assumeBuilddir )
{
if ( assumeBuilddir )
settingsPaths << QDir::current().absoluteFilePath( settings );
+ if ( CalamaresUtils::haveExtraDirs() )
+ for ( auto s : CalamaresUtils::extraConfigDirs() )
+ settingsPaths << ( s + settings );
settingsPaths << CMAKE_INSTALL_FULL_SYSCONFDIR "/calamares/settings.conf"; // String concat
settingsPaths << CalamaresUtils::appDataDir().absoluteFilePath( settings );
}
@@ -182,6 +188,9 @@ brandingFileCandidates( bool assumeBuilddir, const QString& brandingFilename )
{
if ( assumeBuilddir )
brandingPaths << ( QDir::currentPath() + QStringLiteral( "/src/" ) + brandingFilename );
+ if ( CalamaresUtils::haveExtraDirs() )
+ for ( auto s : CalamaresUtils::extraDataDirs() )
+ brandingPaths << ( s + brandingFilename );
brandingPaths << QDir( CMAKE_INSTALL_FULL_SYSCONFDIR "/calamares/" ).absoluteFilePath( brandingFilename );
brandingPaths << CalamaresUtils::appDataDir().absoluteFilePath( brandingFilename);
}
diff --git a/src/calamares/main.cpp b/src/calamares/main.cpp
index 9893e6792..f855b060f 100644
--- a/src/calamares/main.cpp
+++ b/src/calamares/main.cpp
@@ -44,6 +44,8 @@ handle_args( CalamaresApplication& a )
"Verbose output for debugging purposes (0-8).", "level" );
QCommandLineOption configOption( QStringList{ "c", "config"},
"Configuration directory to use, for testing purposes.", "config" );
+ QCommandLineOption xdgOption( QStringList{"X", "xdg-config"},
+ "Use XDG_{CONFIG,DATA}_DIRS as well." );
QCommandLineParser parser;
parser.setApplicationDescription( "Distribution-independent installer framework" );
@@ -53,6 +55,7 @@ handle_args( CalamaresApplication& a )
parser.addOption( debugOption );
parser.addOption( debugLevelOption );
parser.addOption( configOption );
+ parser.addOption( xdgOption );
parser.process( a );
@@ -72,6 +75,8 @@ handle_args( CalamaresApplication& a )
}
if ( parser.isSet( configOption ) )
CalamaresUtils::setAppDataDir( QDir( parser.value( configOption ) ) );
+ if ( parser.isSet( xdgOption ) )
+ CalamaresUtils::setXdgDirs();
}
int
diff --git a/src/calamares/testmain.cpp b/src/calamares/testmain.cpp
index c22342f9a..a8b363209 100644
--- a/src/calamares/testmain.cpp
+++ b/src/calamares/testmain.cpp
@@ -59,6 +59,7 @@ handle_args( QCoreApplication& a )
parser.addOption( debugLevelOption );
parser.addPositionalArgument( "module", "Path or name of module to run." );
+ parser.addPositionalArgument( "config", "Path of job-config file to use.", "[config]");
parser.process( a );
@@ -140,6 +141,8 @@ load_module( const ModuleConfig& moduleConfig )
? moduleDirectory + '/' + name + ".conf"
: moduleConfig.configFile() );
+ cDebug() << "Module" << moduleName << "job-configuration:" << configFile;
+
Calamares::Module* module = Calamares::Module::fromDescriptor(
descriptor, name, configFile, moduleDirectory );
@@ -158,7 +161,7 @@ main( int argc, char* argv[] )
std::unique_ptr< Calamares::Settings > settings_p( new Calamares::Settings( QString(), true ) );
std::unique_ptr< Calamares::JobQueue > jobqueue_p( new Calamares::JobQueue( nullptr ) );
- cDebug() << "Calamares test module-loader" << module.moduleName();
+ cDebug() << "Calamares module-loader testing" << module.moduleName();
Calamares::Module* m = load_module( module );
if ( !m )
{
@@ -175,16 +178,27 @@ main( int argc, char* argv[] )
return 1;
}
- cDebug() << "Module" << m->name() << m->typeString() << m->interfaceString();
+ using TR = Logger::DebugRow;
+ cDebug() << "Module metadata"
+ << TR( "name", m->name() )
+ << TR( "type", m->typeString() )
+ << TR( "interface", m->interfaceString() );
+
+ cDebug() << "Job outputs:";
Calamares::JobList jobList = m->jobs();
unsigned int count = 1;
for ( const auto& p : jobList )
{
- cDebug() << count << p->prettyName();
+ cDebug() << "Job #" << count << "name" << p->prettyName();
Calamares::JobResult r = p->exec();
if ( !r )
- cDebug() << count << ".. failed" << r;
+ {
+ using TR = Logger::DebugRow;
+ cDebug() << count << ".. failed"
+ << TR( "summary", r.message() )
+ << TR( "details", r.details() );
+ }
++count;
}
diff --git a/src/libcalamares/CMakeLists.txt b/src/libcalamares/CMakeLists.txt
index 598d3c313..4bf78176e 100644
--- a/src/libcalamares/CMakeLists.txt
+++ b/src/libcalamares/CMakeLists.txt
@@ -105,6 +105,19 @@ install( TARGETS calamares
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
)
+if ( ECM_FOUND AND BUILD_TESTING )
+ ecm_add_test(
+ Tests.cpp
+ TEST_NAME
+ libcalamarestest
+ LINK_LIBRARIES
+ calamares
+ Qt5::Core
+ Qt5::Test
+ )
+ set_target_properties( libcalamarestest PROPERTIES AUTOMOC TRUE )
+endif()
+
# Make symlink lib/calamares/libcalamares.so to lib/libcalamares.so.VERSION so
# lib/calamares can be used as module path for the Python interpreter.
install( CODE "
diff --git a/src/libcalamares/Tests.cpp b/src/libcalamares/Tests.cpp
new file mode 100644
index 000000000..acf5b03d3
--- /dev/null
+++ b/src/libcalamares/Tests.cpp
@@ -0,0 +1,59 @@
+/* === This file is part of Calamares - ===
+ *
+ * Copyright 2018, Adriaan de Groot
+ *
+ * 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 .
+ */
+
+#include "Tests.h"
+
+#include "utils/Logger.h"
+
+#include
+
+QTEST_GUILESS_MAIN( LibCalamaresTests )
+
+LibCalamaresTests::LibCalamaresTests()
+{
+}
+
+LibCalamaresTests::~LibCalamaresTests()
+{
+}
+
+void
+LibCalamaresTests::initTestCase()
+{
+}
+
+void
+LibCalamaresTests::testDebugLevels()
+{
+ Logger::setupLogLevel( Logger::LOG_DISABLE );
+
+ QCOMPARE( Logger::logLevel(), static_cast( 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 );
+ }
+ }
+}
+
diff --git a/src/libcalamares/Tests.h b/src/libcalamares/Tests.h
new file mode 100644
index 000000000..123655c6e
--- /dev/null
+++ b/src/libcalamares/Tests.h
@@ -0,0 +1,36 @@
+/* === This file is part of Calamares - ===
+ *
+ * Copyright 2018, Adriaan de Groot
+ *
+ * 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 .
+ */
+
+#ifndef TESTS_H
+#define TESTS_H
+
+#include
+
+class LibCalamaresTests : public QObject
+{
+ Q_OBJECT
+public:
+ LibCalamaresTests();
+ ~LibCalamaresTests() override;
+
+private Q_SLOTS:
+ void initTestCase();
+ void testDebugLevels();
+};
+
+#endif
diff --git a/src/libcalamares/utils/CalamaresUtils.cpp b/src/libcalamares/utils/CalamaresUtils.cpp
index 6a892511a..3ab758522 100644
--- a/src/libcalamares/utils/CalamaresUtils.cpp
+++ b/src/libcalamares/utils/CalamaresUtils.cpp
@@ -49,6 +49,9 @@ static QTranslator* s_brandingTranslator = nullptr;
static QTranslator* s_translator = nullptr;
static QString s_translatorLocaleName;
+static bool s_haveExtraDirs = false;
+static QStringList s_extraConfigDirs;
+static QStringList s_extraDataDirs;
static bool
isWritableDir( const QDir& dir )
@@ -94,6 +97,46 @@ setAppDataDir( const QDir& dir )
s_isAppDataDirOverridden = true;
}
+/* Split $ENV{@p name} on :, append to @p l, making sure each ends in / */
+static void
+mungeEnvironment( QStringList& l, const char *name )
+{
+ for ( auto s : QString( qgetenv( name ) ).split(':') )
+ if ( s.endsWith( '/' ) )
+ l << s;
+ else
+ l << ( s + '/' );
+}
+
+void
+setXdgDirs()
+{
+ s_haveExtraDirs = true;
+ mungeEnvironment( s_extraConfigDirs, "XDG_CONFIG_DIRS" );
+ mungeEnvironment( s_extraDataDirs, "XDG_DATA_DIRS" );
+}
+
+QStringList
+extraConfigDirs()
+{
+ if ( s_haveExtraDirs )
+ return s_extraConfigDirs;
+ return QStringList();
+}
+
+QStringList
+extraDataDirs()
+{
+ if ( s_haveExtraDirs )
+ return s_extraDataDirs;
+ return QStringList();
+}
+
+bool
+haveExtraDirs()
+{
+ return s_haveExtraDirs && ( !s_extraConfigDirs.isEmpty() || !s_extraDataDirs.isEmpty() );
+}
bool
isAppDataDirOverridden()
diff --git a/src/libcalamares/utils/CalamaresUtils.h b/src/libcalamares/utils/CalamaresUtils.h
index e64fe4eec..baf7a12dc 100644
--- a/src/libcalamares/utils/CalamaresUtils.h
+++ b/src/libcalamares/utils/CalamaresUtils.h
@@ -79,6 +79,16 @@ namespace CalamaresUtils
DLLEXPORT void setQmlModulesDir( const QDir& dir );
+ /** @brief Setup extra config and data dirs from the XDG variables.
+ */
+ DLLEXPORT void setXdgDirs();
+ /** @brief Are any extra directories configured? */
+ DLLEXPORT bool haveExtraDirs();
+ /** @brief XDG_CONFIG_DIRS, each guaranteed to end with / */
+ DLLEXPORT QStringList extraConfigDirs();
+ /** @brief XDG_DATA_DIRS, each guaranteed to end with / */
+ DLLEXPORT QStringList extraDataDirs();
+
/**
* @brief removeDiacritics replaces letters with diacritics and ligatures with
* alternative forms and digraphs.
diff --git a/src/libcalamares/utils/Logger.cpp b/src/libcalamares/utils/Logger.cpp
index 735414b85..98aa2121f 100644
--- a/src/libcalamares/utils/Logger.cpp
+++ b/src/libcalamares/utils/Logger.cpp
@@ -55,6 +55,18 @@ setupLogLevel(unsigned int level)
s_threshold = level + 1; // Comparison is < in log() function
}
+bool
+logLevelEnabled(unsigned int level)
+{
+ return level < s_threshold;
+}
+
+unsigned int
+logLevel()
+{
+ return s_threshold > 0 ? s_threshold - 1 : 0;
+}
+
static void
log( const char* msg, unsigned int debugLevel, bool toDisk = true )
{
diff --git a/src/libcalamares/utils/Logger.h b/src/libcalamares/utils/Logger.h
index dba386eae..0cb4b494f 100644
--- a/src/libcalamares/utils/Logger.h
+++ b/src/libcalamares/utils/Logger.h
@@ -89,6 +89,12 @@ namespace Logger
*/
DLLEXPORT void setupLogLevel( unsigned int level );
+ /** @brief Return the configured log-level. */
+ DLLEXPORT unsigned int logLevel();
+
+ /** @brief Would the given @p level really be logged? */
+ DLLEXPORT bool logLevelEnabled( unsigned int level );
+
/**
* @brief Row-oriented formatted logging.
*
diff --git a/src/libcalamaresui/modulesystem/Module.cpp b/src/libcalamaresui/modulesystem/Module.cpp
index 8d92c37ad..ef629ac4d 100644
--- a/src/libcalamaresui/modulesystem/Module.cpp
+++ b/src/libcalamaresui/modulesystem/Module.cpp
@@ -145,8 +145,19 @@ moduleConfigurationCandidates( bool assumeBuildDir, const QString& moduleName, c
paths << CalamaresUtils::appDataDir().absoluteFilePath( QString( "modules/%1" ).arg( configFileName ) );
else
{
+ // If an absolute path is given, in debug mode, look for it
+ // first. The case contains('/'), below, will add the absolute
+ // path a second time, though.
+ if ( assumeBuildDir && configFileName.startsWith( '/' ) )
+ paths << configFileName;
if ( assumeBuildDir )
paths << QDir().absoluteFilePath(QString( "src/modules/%1/%2" ).arg( moduleName ).arg( configFileName ) );
+ if ( assumeBuildDir && configFileName.contains( '/' ) )
+ paths << QDir().absoluteFilePath( configFileName );
+
+ if ( CalamaresUtils::haveExtraDirs() )
+ for ( auto s : CalamaresUtils::extraConfigDirs() )
+ paths << ( s + QString( "modules/%1" ).arg( configFileName ) );
paths << QString( "/etc/calamares/modules/%1" ).arg( configFileName );
paths << CalamaresUtils::appDataDir().absoluteFilePath( QString( "modules/%1" ).arg( configFileName ) );
@@ -168,6 +179,7 @@ Module::loadConfigurationFile( const QString& configFileName ) //throws YAML::Ex
YAML::Node doc = YAML::Load( ba.constData() );
if ( doc.IsNull() )
{
+ cDebug() << "Found empty module configuration" << path;
// Special case: empty config files are valid,
// but aren't a map.
return;
@@ -178,14 +190,13 @@ Module::loadConfigurationFile( const QString& configFileName ) //throws YAML::Ex
return;
}
+ cDebug() << "Loaded module configuration" << path;
m_configurationMap = CalamaresUtils::yamlMapToVariant( doc ).toMap();
m_emergency = m_maybe_emergency
&& m_configurationMap.contains( EMERGENCY )
&& m_configurationMap[ EMERGENCY ].toBool();
return;
}
- else
- continue;
}
}
diff --git a/src/modules/contextualprocess/CMakeLists.txt b/src/modules/contextualprocess/CMakeLists.txt
index 2cf8d3879..f75946b58 100644
--- a/src/modules/contextualprocess/CMakeLists.txt
+++ b/src/modules/contextualprocess/CMakeLists.txt
@@ -8,10 +8,7 @@ calamares_add_plugin( contextualprocess
SHARED_LIB
)
-if( ECM_FOUND )
- find_package( Qt5 COMPONENTS Test REQUIRED )
- include( ECMAddTests )
-
+if( ECM_FOUND AND BUILD_TESTING )
ecm_add_test(
Tests.cpp
ContextualProcessJob.cpp # Builds it a second time
diff --git a/src/modules/dummypythonqt/lang/zh_CN/LC_MESSAGES/dummypythonqt.mo b/src/modules/dummypythonqt/lang/zh_CN/LC_MESSAGES/dummypythonqt.mo
index 0dac94ca0..240d5c4db 100644
Binary files a/src/modules/dummypythonqt/lang/zh_CN/LC_MESSAGES/dummypythonqt.mo and b/src/modules/dummypythonqt/lang/zh_CN/LC_MESSAGES/dummypythonqt.mo differ
diff --git a/src/modules/dummypythonqt/lang/zh_CN/LC_MESSAGES/dummypythonqt.po b/src/modules/dummypythonqt/lang/zh_CN/LC_MESSAGES/dummypythonqt.po
index 14bf4463a..564bcdabc 100644
--- a/src/modules/dummypythonqt/lang/zh_CN/LC_MESSAGES/dummypythonqt.po
+++ b/src/modules/dummypythonqt/lang/zh_CN/LC_MESSAGES/dummypythonqt.po
@@ -8,9 +8,9 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2017-09-04 08:16-0400\n"
+"POT-Creation-Date: 2018-06-18 07:46-0400\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
-"Last-Translator: Mingcong Bai , 2017\n"
+"Last-Translator: soenggam , 2017\n"
"Language-Team: Chinese (China) (https://www.transifex.com/calamares/teams/20061/zh_CN/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
@@ -24,7 +24,7 @@ msgstr "按我按我!"
#: src/modules/dummypythonqt/main.py:94
msgid "A new QLabel."
-msgstr "一个平淡无奇的 QLabel。"
+msgstr "一个新的QLabel。"
#: src/modules/dummypythonqt/main.py:97
msgid "Dummy PythonQt ViewStep"
diff --git a/src/modules/fsresizer/CMakeLists.txt b/src/modules/fsresizer/CMakeLists.txt
new file mode 100644
index 000000000..e339b2799
--- /dev/null
+++ b/src/modules/fsresizer/CMakeLists.txt
@@ -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()
diff --git a/src/modules/fsresizer/ResizeFSJob.cpp b/src/modules/fsresizer/ResizeFSJob.cpp
new file mode 100644
index 000000000..4df41a7d4
--- /dev/null
+++ b/src/modules/fsresizer/ResizeFSJob.cpp
@@ -0,0 +1,347 @@
+/* === This file is part of Calamares - ===
+ *
+ * Copyright 2018, Adriaan de Groot
+ *
+ * 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 .
+ */
+
+#include "ResizeFSJob.h"
+
+#include
+#include
+#include
+
+#include
+#include
+#include
+#include
+#include
+#include
+
+#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
+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(); )
diff --git a/src/modules/fsresizer/ResizeFSJob.h b/src/modules/fsresizer/ResizeFSJob.h
new file mode 100644
index 000000000..c34ccb865
--- /dev/null
+++ b/src/modules/fsresizer/ResizeFSJob.h
@@ -0,0 +1,122 @@
+/* === This file is part of Calamares - ===
+ *
+ * Copyright 2018, Adriaan de Groot
+ *
+ * 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 .
+ */
+
+#ifndef RESIZEFSJOB_H
+#define RESIZEFSJOB_H
+
+#include
+#include
+
+#include
+
+#include
+
+#include
+
+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;
+ /** @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
diff --git a/src/modules/fsresizer/Tests.cpp b/src/modules/fsresizer/Tests.cpp
new file mode 100644
index 000000000..255153fa2
--- /dev/null
+++ b/src/modules/fsresizer/Tests.cpp
@@ -0,0 +1,126 @@
+/* === This file is part of Calamares - ===
+ *
+ * Copyright 2017-2018, Adriaan de Groot
+ *
+ * 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 .
+ */
+
+#include "Tests.h"
+
+#include "GlobalStorage.h"
+#include "JobQueue.h"
+#include "Settings.h"
+
+#include "utils/Logger.h"
+#include "utils/YamlUtils.h"
+
+#include
+
+#include
+
+#include
+#include
+
+#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 );
+}
diff --git a/src/modules/fsresizer/Tests.h b/src/modules/fsresizer/Tests.h
new file mode 100644
index 000000000..958c0e655
--- /dev/null
+++ b/src/modules/fsresizer/Tests.h
@@ -0,0 +1,39 @@
+/* === This file is part of Calamares - ===
+ *
+ * Copyright 2018, Adriaan de Groot
+ *
+ * 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 .
+ */
+
+#ifndef TESTS_H
+#define TESTS_H
+
+#include
+
+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
diff --git a/src/modules/fsresizer/fsresizer.conf b/src/modules/fsresizer/fsresizer.conf
new file mode 100644
index 000000000..33329248d
--- /dev/null
+++ b/src/modules/fsresizer/fsresizer.conf
@@ -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
diff --git a/src/modules/keyboard/SetKeyboardLayoutJob.cpp b/src/modules/keyboard/SetKeyboardLayoutJob.cpp
index 02d807045..75c52bb51 100644
--- a/src/modules/keyboard/SetKeyboardLayoutJob.cpp
+++ b/src/modules/keyboard/SetKeyboardLayoutJob.cpp
@@ -65,6 +65,8 @@ SetKeyboardLayoutJob::prettyName() const
QString
SetKeyboardLayoutJob::findConvertedKeymap( const QString& convertedKeymapPath ) const
{
+ cDebug() << "Looking for converted keymap in" << convertedKeymapPath;
+
// No search path supplied, assume the distribution does not provide
// converted keymaps
if ( convertedKeymapPath.isEmpty() )
@@ -76,8 +78,7 @@ SetKeyboardLayoutJob::findConvertedKeymap( const QString& convertedKeymapPath )
if ( convertedKeymapDir.exists( name + ".map" )
|| convertedKeymapDir.exists( name + ".map.gz" ) )
{
- cDebug() << "Found converted keymap" << name;
-
+ cDebug() << ".. Found converted keymap" << name;
return name;
}
@@ -88,6 +89,8 @@ SetKeyboardLayoutJob::findConvertedKeymap( const QString& convertedKeymapPath )
QString
SetKeyboardLayoutJob::findLegacyKeymap() const
{
+ cDebug() << "Looking for legacy keymap in QRC";
+
int bestMatching = 0;
QString name;
@@ -137,7 +140,7 @@ SetKeyboardLayoutJob::findLegacyKeymap() const
// The best matching entry so far, then let's save that
if ( matching >= qMax( bestMatching, 1 ) )
{
- cDebug() << "Found legacy keymap" << mapping[0]
+ cDebug() << ".. Found legacy keymap" << mapping[0]
<< "with score" << matching;
if ( matching > bestMatching )
diff --git a/src/modules/keyboard/kbd-model-map b/src/modules/keyboard/kbd-model-map
index b00639b7f..49ec4ad75 100644
--- a/src/modules/keyboard/kbd-model-map
+++ b/src/modules/keyboard/kbd-model-map
@@ -6,6 +6,9 @@
# This is the version from 534644b7be7b240eb0fbbe06e20cbecbe8206767,
# committed 2015-01-22 01:07:24 .
#
+# Updates:
+# - 2018-09-26 Added "Austrian" keyboard (de at). Issue #1035
+#
# Generated from system-config-keyboard's model list
# consolelayout xlayout xmodel xvariant xoptions
sg ch pc105 de_nodeadkeys terminate:ctrl_alt_bksp
@@ -14,8 +17,8 @@ mk-utf mk,us pc105 - terminate:ctrl_alt_bksp,grp:shifts_toggle,grp_led:scrol
trq tr pc105 - terminate:ctrl_alt_bksp
uk gb pc105 - terminate:ctrl_alt_bksp
is-latin1 is pc105 - terminate:ctrl_alt_bksp
-at de pc105 - terminate:ctrl_alt_bksp
de de pc105 - terminate:ctrl_alt_bksp
+de at pc105 - terminate:ctrl_alt_bksp
la-latin1 latam pc105 - terminate:ctrl_alt_bksp
us us pc105+inet - terminate:ctrl_alt_bksp
ko kr pc105 - terminate:ctrl_alt_bksp
diff --git a/src/modules/locale/CMakeLists.txt b/src/modules/locale/CMakeLists.txt
index 24259d797..576f2e16e 100644
--- a/src/modules/locale/CMakeLists.txt
+++ b/src/modules/locale/CMakeLists.txt
@@ -1,9 +1,3 @@
-find_package(ECM ${ECM_VERSION} NO_MODULE)
-if( ECM_FOUND AND BUILD_TESTING )
- include( ECMAddTests )
- find_package( Qt5 COMPONENTS Core Test REQUIRED )
-endif()
-
# When debugging the timezone widget, add this debugging definition
# to have a debugging-friendly timezone widget, debug logging,
# and no intrusive timezone-setting while clicking around.
diff --git a/src/modules/localecfg/main.py b/src/modules/localecfg/main.py
index 62a00b738..713b1e321 100644
--- a/src/modules/localecfg/main.py
+++ b/src/modules/localecfg/main.py
@@ -134,7 +134,7 @@ def run():
if os.path.exists(target_locale_gen_bak):
shutil.copy2(target_locale_gen_bak, target_locale_gen)
libcalamares.utils.debug("Restored backup {!s} -> {!s}"
- .format(target_locale_gen_bak).format(target_locale_gen))
+ .format(target_locale_gen_bak, target_locale_gen))
# run locale-gen if detected; this *will* cause an exception
# if the live system has locale.gen, but the target does not:
diff --git a/src/modules/partition/core/DeviceList.cpp b/src/modules/partition/core/DeviceList.cpp
index 4a353efb4..f51eec047 100644
--- a/src/modules/partition/core/DeviceList.cpp
+++ b/src/modules/partition/core/DeviceList.cpp
@@ -113,28 +113,32 @@ QList< Device* > getDevices( DeviceType which, qint64 minimumSize )
// Remove the device which contains / from the list
for ( DeviceList::iterator it = devices.begin(); it != devices.end(); )
- if ( ! ( *it ) ||
- ( *it )->deviceNode().startsWith( "/dev/zram" )
+ if ( !( *it ) )
+ {
+ cDebug() << " .. Skipping nullptr device";
+ it = erase( devices, it);
+ }
+ else if ( ( *it )->deviceNode().startsWith( "/dev/zram" )
)
{
cDebug() << " .. Removing zram" << it;
- it = erase(devices, it );
+ it = erase( devices, it );
}
else if ( writableOnly && hasRootPartition( *it ) )
{
cDebug() << " .. Removing device with root filesystem (/) on it" << it;
- it = erase(devices, it );
+ it = erase( devices, it );
}
else if ( writableOnly && isIso9660( *it ) )
{
cDebug() << " .. Removing device with iso9660 filesystem (probably a CD) on it" << it;
- it = erase(devices, it );
+ it = erase( devices, it );
}
else if ( (minimumSize >= 0) && !( (*it)->capacity() > minimumSize ) )
{
cDebug() << " .. Removing too-small" << it;
- it = erase(devices, it );
+ it = erase( devices, it );
}
else
++it;
diff --git a/src/modules/partition/core/PartitionCoreModule.cpp b/src/modules/partition/core/PartitionCoreModule.cpp
index 0913664ca..f41142b6a 100644
--- a/src/modules/partition/core/PartitionCoreModule.cpp
+++ b/src/modules/partition/core/PartitionCoreModule.cpp
@@ -509,18 +509,8 @@ PartitionCoreModule::jobs() const
lst << info->jobs;
devices << info->device.data();
}
- cDebug() << "Creating FillGlobalStorageJob with bootLoader path" << m_bootLoaderInstallPath;
lst << Calamares::job_ptr( new FillGlobalStorageJob( devices, m_bootLoaderInstallPath ) );
-
- QStringList jobsDebug;
- foreach ( auto job, lst )
- jobsDebug.append( job->prettyName() );
-
- cDebug() << "PartitionCodeModule has been asked for jobs. About to return:";
- for ( const auto item: jobsDebug )
- cDebug() << " .." << item;
-
return lst;
}
@@ -573,9 +563,9 @@ PartitionCoreModule::dumpQueue() const
cDebug() << "# Queue:";
for ( auto info : m_deviceInfos )
{
- cDebug() << " .. Device:" << info->device->name();
+ cDebug() << "## Device:" << info->device->name();
for ( auto job : info->jobs )
- cDebug() << " .." << job->prettyName();
+ cDebug() << "-" << job->prettyName();
}
}
diff --git a/src/modules/partition/core/PartitionIterator.cpp b/src/modules/partition/core/PartitionIterator.cpp
index 5ed48fd91..8301835c6 100644
--- a/src/modules/partition/core/PartitionIterator.cpp
+++ b/src/modules/partition/core/PartitionIterator.cpp
@@ -18,7 +18,7 @@
* along with Calamares. If not, see .
*/
-#include
+#include "PartitionIterator.h"
// KPMcore
#include
diff --git a/src/modules/partition/gui/ChoicePage.cpp b/src/modules/partition/gui/ChoicePage.cpp
index abe7795c0..9bc571459 100644
--- a/src/modules/partition/gui/ChoicePage.cpp
+++ b/src/modules/partition/gui/ChoicePage.cpp
@@ -1161,6 +1161,13 @@ force_uncheck(QButtonGroup* grp, PrettyRadioButton* button)
grp->setExclusive( true );
}
+static inline QDebug&
+operator <<( QDebug& s, PartitionIterator& it )
+{
+ s << ( ( *it ) ? ( *it )->deviceNode() : QString( "" ) );
+ return s;
+}
+
/**
* @brief ChoicePage::setupActions happens every time a new Device* is selected in the
* device picker. Sets up the text and visibility of the partitioning actions based
@@ -1174,6 +1181,9 @@ ChoicePage::setupActions()
OsproberEntryList osproberEntriesForCurrentDevice =
getOsproberEntriesForDevice( currentDevice );
+ cDebug() << "Setting up actions for" << currentDevice->deviceNode()
+ << "with" << osproberEntriesForCurrentDevice.count() << "entries.";
+
if ( currentDevice->partitionTable() )
m_deviceInfoWidget->setPartitionTableType( currentDevice->partitionTable()->type() );
else
@@ -1190,18 +1200,30 @@ ChoicePage::setupActions()
#ifdef WITH_KPMCOREGT33
if ( currentDevice->type() == Device::Type::SoftwareRAID_Device &&
static_cast< SoftwareRAID* >(currentDevice)->status() == SoftwareRAID::Status::Inactive )
+ {
+ cDebug() << ".. part of an inactive RAID device";
isInactiveRAID = true;
+ }
#endif
for ( auto it = PartitionIterator::begin( currentDevice );
it != PartitionIterator::end( currentDevice ); ++it )
{
if ( PartUtils::canBeResized( *it ) )
+ {
+ cDebug() << ".. contains resizable" << it;
atLeastOneCanBeResized = true;
+ }
if ( PartUtils::canBeReplaced( *it ) )
+ {
+ cDebug() << ".. contains replacable" << it;
atLeastOneCanBeReplaced = true;
+ }
if ( (*it)->isMounted() )
+ {
+ cDebug() << ".. contains mounted" << it;
atLeastOneIsMounted = true;
+ }
}
if ( osproberEntriesForCurrentDevice.count() == 0 )
@@ -1318,7 +1340,12 @@ ChoicePage::setupActions()
if ( !atLeastOneIsMounted && !isInactiveRAID )
m_eraseButton->show(); // None mounted
else
+ {
+ cDebug() << "Erase button suppressed"
+ << "mount?" << atLeastOneIsMounted
+ << "raid?" << isInactiveRAID;
force_uncheck( m_grp, m_eraseButton );
+ }
bool isEfi = PartUtils::isEfiSystem();
bool efiSystemPartitionFound = !m_core->efiSystemPartitions().isEmpty();
diff --git a/src/modules/partition/jobs/CreatePartitionTableJob.cpp b/src/modules/partition/jobs/CreatePartitionTableJob.cpp
index 3ae201d62..937b8437d 100644
--- a/src/modules/partition/jobs/CreatePartitionTableJob.cpp
+++ b/src/modules/partition/jobs/CreatePartitionTableJob.cpp
@@ -20,6 +20,8 @@
#include "jobs/CreatePartitionTableJob.h"
+#include "core/PartitionIterator.h"
+
#include "utils/Logger.h"
// KPMcore
@@ -65,6 +67,14 @@ CreatePartitionTableJob::prettyStatusMessage() const
}
+static inline QDebug&
+operator <<( QDebug& s, PartitionIterator& it )
+{
+ s << ( ( *it ) ? ( *it )->deviceNode() : QString( "" ) );
+ return s;
+}
+
+
Calamares::JobResult
CreatePartitionTableJob::exec()
{
@@ -73,33 +83,28 @@ CreatePartitionTableJob::exec()
PartitionTable* table = m_device->partitionTable();
cDebug() << "Creating new partition table of type" << table->typeName()
- << " - Uncommitted yet: " << table;
+ << ", uncommitted yet:";
- QProcess lsblk;
- lsblk.setProgram( "lsblk" );
- lsblk.setProcessChannelMode( QProcess::MergedChannels );
- lsblk.start();
- lsblk.waitForFinished();
+ if ( Logger::logLevelEnabled( Logger::LOGDEBUG ) )
+ {
+ for ( auto it = PartitionIterator::begin( table );
+ it != PartitionIterator::end( table ); ++it )
+ cDebug() << *it;
- QByteArray byte = lsblk.readAllStandardOutput();
- QStringList lines = QString(byte).split(("\n"),QString::SkipEmptyParts);
- cDebug() << "CreatePartitionTableJob asked for lsblk output:";
+ QProcess lsblk;
+ lsblk.setProgram( "lsblk" );
+ lsblk.setProcessChannelMode( QProcess::MergedChannels );
+ lsblk.start();
+ lsblk.waitForFinished();
+ cDebug() << "lsblk:\n" << lsblk.readAllStandardOutput();
- for (const auto line: lines)
- cDebug() << " .." << line;
-
- QProcess mount;
- mount.setProgram( "mount" );
- mount.setProcessChannelMode( QProcess::MergedChannels );
- mount.start();
- mount.waitForFinished();
-
- QByteArray mbyte = mount.readAllStandardOutput();
- QStringList mlines = QString(mbyte).split(("\n"),QString::SkipEmptyParts);
- cDebug() << "CreatePartitionTableJob asked for mount output:";
-
- for (const auto mline: mlines)
- cDebug() << " .." << mline;
+ QProcess mount;
+ mount.setProgram( "mount" );
+ mount.setProcessChannelMode( QProcess::MergedChannels );
+ mount.start();
+ mount.waitForFinished();
+ cDebug() << "mount:\n" << mount.readAllStandardOutput();
+ }
CreatePartitionTableOperation op(*m_device, table);
op.setStatus(Operation::StatusRunning);
diff --git a/src/modules/partition/jobs/FillGlobalStorageJob.cpp b/src/modules/partition/jobs/FillGlobalStorageJob.cpp
index 43a5f3904..597d62a82 100644
--- a/src/modules/partition/jobs/FillGlobalStorageJob.cpp
+++ b/src/modules/partition/jobs/FillGlobalStorageJob.cpp
@@ -56,9 +56,12 @@ findPartitionUuids( QList < Device* > devices )
QString path = p->partitionPath();
QString uuid = p->fileSystem().readUUID( p->partitionPath() );
hash.insert( path, uuid );
+ cDebug() << ".. added path=" << path << "UUID=" << uuid;
}
}
- cDebug() << hash;
+
+ if ( hash.isEmpty() )
+ cDebug() << ".. no UUIDs found.";
return hash;
}
@@ -90,10 +93,16 @@ mapForPartition( Partition* partition, const QString& uuid )
dynamic_cast< FS::luks& >( partition->fileSystem() ).innerFS() )
map[ "fs" ] = dynamic_cast< FS::luks& >( partition->fileSystem() ).innerFS()->name();
map[ "uuid" ] = uuid;
- cDebug() << partition->partitionPath()
- << "mtpoint:" << PartitionInfo::mountPoint( partition )
- << "fs:" << map[ "fs" ] << '(' << map[ "fsName" ] << ')'
- << uuid;
+
+ // Debugging for inside the loop in createPartitionList(),
+ // so indent a bit
+ Logger::CLog deb = cDebug();
+ using TR = Logger::DebugRow;
+ deb << " .. mapping for" << partition->partitionPath() << partition->deviceNode()
+ << TR( "mtpoint:", PartitionInfo::mountPoint( partition ) )
+ << TR( "fs:", map[ "fs" ].toString() )
+ << TR( "fsname", map[ "fsName" ].toString() )
+ << TR( "uuid", uuid );
if ( partition->roles().has( PartitionRole::Luks ) )
{
@@ -104,7 +113,7 @@ mapForPartition( Partition* partition, const QString& uuid )
map[ "luksMapperName" ] = luksFs->mapperName().split( "/" ).last();
map[ "luksUuid" ] = getLuksUuid( partition->partitionPath() );
map[ "luksPassphrase" ] = luksFs->passphrase();
- cDebug() << "luksMapperName:" << map[ "luksMapperName" ];
+ deb << TR( "luksMapperName:", map[ "luksMapperName" ].toString() );
}
}
@@ -215,9 +224,11 @@ FillGlobalStorageJob::createPartitionList() const
cDebug() << "Writing to GlobalStorage[\"partitions\"]";
for ( auto device : m_devices )
{
+ cDebug() << ".. partitions on" << device->deviceNode();
for ( auto it = PartitionIterator::begin( device );
it != PartitionIterator::end( device ); ++it )
{
+ // Debug-logging is done when creating the map
lst << mapForPartition( *it, hash.value( ( *it )->partitionPath() ) );
}
}
diff --git a/src/modules/partition/jobs/SetPartitionFlagsJob.cpp b/src/modules/partition/jobs/SetPartitionFlagsJob.cpp
index 7f6169bbe..fee987479 100644
--- a/src/modules/partition/jobs/SetPartitionFlagsJob.cpp
+++ b/src/modules/partition/jobs/SetPartitionFlagsJob.cpp
@@ -132,6 +132,10 @@ SetPartFlagsJob::prettyStatusMessage() const
Calamares::JobResult
SetPartFlagsJob::exec()
{
+ cDebug() << "Setting flags on" << m_device->deviceNode()
+ << "partition" << partition()->deviceNode()
+ << "to" << m_flags;
+
Report report ( nullptr );
SetPartFlagsOperation op( *m_device, *partition(), m_flags );
op.setStatus( Operation::StatusRunning );
diff --git a/src/modules/partition/tests/CMakeLists.txt b/src/modules/partition/tests/CMakeLists.txt
index 68474287e..7b40c34a5 100644
--- a/src/modules/partition/tests/CMakeLists.txt
+++ b/src/modules/partition/tests/CMakeLists.txt
@@ -1,6 +1,4 @@
-find_package( Qt5 COMPONENTS Gui Test REQUIRED )
-
-include( ECMAddTests )
+find_package( Qt5 COMPONENTS Gui REQUIRED )
set( PartitionModule_SOURCE_DIR .. )
@@ -23,13 +21,15 @@ include_directories(
${CMAKE_CURRENT_BINARY_DIR}
)
-ecm_add_test( ${partitionjobtests_SRCS}
- TEST_NAME partitionjobtests
- LINK_LIBRARIES
- ${CALAMARES_LIBRARIES}
- kpmcore
- Qt5::Core
- Qt5::Test
-)
+if( ECM_FOUND AND BUILD_TESTING )
+ ecm_add_test( ${partitionjobtests_SRCS}
+ TEST_NAME partitionjobtests
+ LINK_LIBRARIES
+ ${CALAMARES_LIBRARIES}
+ kpmcore
+ Qt5::Core
+ Qt5::Test
+ )
-set_target_properties( partitionjobtests PROPERTIES AUTOMOC TRUE )
+ set_target_properties( partitionjobtests PROPERTIES AUTOMOC TRUE )
+endif()
diff --git a/src/modules/preservefiles/CMakeLists.txt b/src/modules/preservefiles/CMakeLists.txt
index 1ac979d1b..c1021eeda 100644
--- a/src/modules/preservefiles/CMakeLists.txt
+++ b/src/modules/preservefiles/CMakeLists.txt
@@ -4,6 +4,7 @@ calamares_add_plugin( preservefiles
TYPE job
EXPORT_MACRO PLUGINDLLEXPORT_PRO
SOURCES
+ permissions.cpp
PreserveFiles.cpp
LINK_PRIVATE_LIBRARIES
calamares
diff --git a/src/modules/preservefiles/PreserveFiles.cpp b/src/modules/preservefiles/PreserveFiles.cpp
index 0fe1d278b..2c1b85103 100644
--- a/src/modules/preservefiles/PreserveFiles.cpp
+++ b/src/modules/preservefiles/PreserveFiles.cpp
@@ -18,6 +18,8 @@
#include "PreserveFiles.h"
+#include "permissions.h"
+
#include "CalamaresVersion.h"
#include "JobQueue.h"
#include "GlobalStorage.h"
@@ -83,6 +85,38 @@ PreserveFiles::prettyName() const
return tr( "Saving files for later ..." );
}
+static bool
+copy_file( const QString& source, const QString& dest )
+{
+ QFile sourcef( source );
+ if ( !sourcef.open( QFile::ReadOnly ) )
+ {
+ cWarning() << "Could not read" << source;
+ return false;
+ }
+
+ QFile destf( dest );
+ if ( !destf.open( QFile::WriteOnly ) )
+ {
+ sourcef.close();
+ cWarning() << "Could not open" << destf.fileName() << "for writing; could not copy" << source;
+ return false;
+ }
+
+ QByteArray b;
+ do
+ {
+ b = sourcef.read( 1_MiB );
+ destf.write( b );
+ }
+ while ( b.count() > 0 );
+
+ sourcef.close();
+ destf.close();
+
+ return true;
+}
+
Calamares::JobResult PreserveFiles::exec()
{
if ( m_items.isEmpty() )
@@ -96,7 +130,8 @@ Calamares::JobResult PreserveFiles::exec()
for ( const auto& it : m_items )
{
QString source = it.source;
- QString dest = prefix + atReplacements( it.dest );
+ QString bare_dest = atReplacements( it.dest );
+ QString dest = prefix + bare_dest;
if ( it.type == ItemType::Log )
source = Logger::logFile();
@@ -111,32 +146,29 @@ Calamares::JobResult PreserveFiles::exec()
cWarning() << "Skipping unnamed source file for" << dest;
else
{
- QFile sourcef( source );
- if ( !sourcef.open( QFile::ReadOnly ) )
+ if ( copy_file( source, dest ) )
{
- cWarning() << "Could not read" << source;
- continue;
+ if ( it.perm.isValid() )
+ {
+ auto s_p = CalamaresUtils::System::instance();
+
+ int r;
+
+ r = s_p->targetEnvCall( QStringList{ "chown", it.perm.username(), bare_dest } );
+ if ( r )
+ cWarning() << "Could not chown target" << bare_dest;
+
+ r = s_p->targetEnvCall( QStringList{ "chgrp", it.perm.group(), bare_dest } );
+ if ( r )
+ cWarning() << "Could not chgrp target" << bare_dest;
+
+ r = s_p->targetEnvCall( QStringList{ "chmod", it.perm.octal(), bare_dest } );
+ if ( r )
+ cWarning() << "Could not chmod target" << bare_dest;
+ }
+
+ ++count;
}
-
- QFile destf( dest );
- if ( !destf.open( QFile::WriteOnly ) )
- {
- sourcef.close();
- cWarning() << "Could not open" << destf.fileName() << "for writing; could not copy" << source;
- continue;
- }
-
- QByteArray b;
- do
- {
- b = sourcef.read( 1_MiB );
- destf.write( b );
- }
- while ( b.count() > 0 );
-
- sourcef.close();
- destf.close();
- ++count;
}
}
@@ -160,6 +192,10 @@ void PreserveFiles::setConfigurationMap(const QVariantMap& configurationMap)
return;
}
+ QString defaultPermissions = configurationMap[ "perm" ].toString();
+ if ( defaultPermissions.isEmpty() )
+ defaultPermissions = QStringLiteral( "root:root:0400" );
+
QVariantList l = files.toList();
unsigned int c = 0;
for ( const auto& li : l )
@@ -168,7 +204,7 @@ void PreserveFiles::setConfigurationMap(const QVariantMap& configurationMap)
{
QString filename = li.toString();
if ( !filename.isEmpty() )
- m_items.append( Item{ filename, filename, ItemType::Path } );
+ m_items.append( Item{ filename, filename, Permissions( defaultPermissions ), ItemType::Path } );
else
cDebug() << "Empty filename for preservefiles, item" << c;
}
@@ -181,6 +217,9 @@ void PreserveFiles::setConfigurationMap(const QVariantMap& configurationMap)
( from == "log" ) ? ItemType::Log :
( from == "config" ) ? ItemType::Config :
ItemType::None;
+ QString perm = map[ "perm" ].toString();
+ if ( perm.isEmpty() )
+ perm = defaultPermissions;
if ( dest.isEmpty() )
{
@@ -192,7 +231,7 @@ void PreserveFiles::setConfigurationMap(const QVariantMap& configurationMap)
}
else
{
- m_items.append( Item{ QString(), dest, t } );
+ m_items.append( Item{ QString(), dest, Permissions( perm ), t } );
}
}
else
diff --git a/src/modules/preservefiles/PreserveFiles.h b/src/modules/preservefiles/PreserveFiles.h
index 0c9216336..ed2fe889c 100644
--- a/src/modules/preservefiles/PreserveFiles.h
+++ b/src/modules/preservefiles/PreserveFiles.h
@@ -24,11 +24,11 @@
#include
#include "CppJob.h"
+#include "PluginDllMacro.h"
#include "utils/PluginFactory.h"
-#include "PluginDllMacro.h"
-
+#include "permissions.h"
class PLUGINDLLEXPORT PreserveFiles : public Calamares::CppJob
{
@@ -46,6 +46,7 @@ class PLUGINDLLEXPORT PreserveFiles : public Calamares::CppJob
{
QString source;
QString dest;
+ Permissions perm;
ItemType type;
} ;
diff --git a/src/modules/preservefiles/permissions.cpp b/src/modules/preservefiles/permissions.cpp
new file mode 100644
index 000000000..a3f8ac136
--- /dev/null
+++ b/src/modules/preservefiles/permissions.cpp
@@ -0,0 +1,75 @@
+/* === This file is part of Calamares - ===
+ *
+ * Copyright (C) 2018 Scott Harvey
+ *
+ * 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 .
+ *
+ */
+
+#include
+#include
+#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;
+
+}
+
+
+
+
+
+
diff --git a/src/modules/preservefiles/permissions.h b/src/modules/preservefiles/permissions.h
new file mode 100644
index 000000000..4cb70a2c2
--- /dev/null
+++ b/src/modules/preservefiles/permissions.h
@@ -0,0 +1,62 @@
+/* === This file is part of Calamares - ===
+ *
+ * Copyright (C) 2018 Scott Harvey
+ *
+ * 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 .
+ *
+ */
+
+#ifndef PERMISSIONS_H
+#define PERMISSIONS_H
+
+#include
+
+/**
+ * @brief The Permissions class takes a QString @p in the form of
+ * ::, 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
+ * , , and (permissions), where 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
diff --git a/src/modules/preservefiles/preservefiles.conf b/src/modules/preservefiles/preservefiles.conf
index ab9114d20..671a308cc 100644
--- a/src/modules/preservefiles/preservefiles.conf
+++ b/src/modules/preservefiles/preservefiles.conf
@@ -9,13 +9,18 @@
# as the source).
# - a map with a *dest* key. The *dest* value is a path interpreted in the
# target system (if dontChroot is true, in the host system). Relative paths
-# are not recommended. There are two possible other keys in the map:
+# are not recommended. There are three possible other keys in the map:
# - *from*, which must have one of the values, below; it is used to
# preserve files whose pathname is known to Calamares internally.
# - *src*, to refer to a path interpreted in the host system. Relative
# paths are not recommended, and are interpreted relative to where
# Calamares is being run.
-# Only one of the two other keys (either *from* or *src*) may be set.
+# - *perm*, is a colon-separated tuple of ::
+# where is in octal (e.g. 4777 for wide-open, 0400 for read-only
+# by owner). If set, the file's ownership and permissions are set to
+# those values within the target system; if not set, no permissions
+# are changed.
+# Only one of the two source keys (either *from* or *src*) may be set.
#
# The target filename is modified as follows:
# - `@@ROOT@@` is replaced by the path to the target root (may be /)
@@ -32,5 +37,13 @@ files:
- /etc/oem-information
- from: log
dest: /root/install.log
+ perm: root:wheel:644
- from: config
dest: /root/install.cfg
+ perm: root:wheel:400
+
+# The *perm* key contains a default value to apply to all files listed
+# above that do not have a *perm* key of their own. If not set,
+# root:root:0400 (highly restrictive) is used.
+#
+# perm: "root:root:0400"
diff --git a/src/modules/shellprocess/CMakeLists.txt b/src/modules/shellprocess/CMakeLists.txt
index 51d4c4a4c..82ae8b911 100644
--- a/src/modules/shellprocess/CMakeLists.txt
+++ b/src/modules/shellprocess/CMakeLists.txt
@@ -8,10 +8,7 @@ calamares_add_plugin( shellprocess
SHARED_LIB
)
-if( ECM_FOUND )
- find_package( Qt5 COMPONENTS Test REQUIRED )
- include( ECMAddTests )
-
+if( ECM_FOUND AND BUILD_TESTING )
ecm_add_test(
Tests.cpp
TEST_NAME
diff --git a/src/modules/test_conf.cpp b/src/modules/test_conf.cpp
index b5362d25a..ca6b72cc7 100644
--- a/src/modules/test_conf.cpp
+++ b/src/modules/test_conf.cpp
@@ -87,7 +87,7 @@ int main(int argc, char** argv)
if ( !doc.IsMap() )
{
cerr << "WARNING:" << filename << '\n';
- cerr << "WARNING: not-a-YAML-map\n";
+ cerr << "WARNING: not-a-YAML-map (type=" << doc.Type() << ")\n";
return 1;
}
diff --git a/src/modules/users/CMakeLists.txt b/src/modules/users/CMakeLists.txt
index 16e235fd5..207ffbb3a 100644
--- a/src/modules/users/CMakeLists.txt
+++ b/src/modules/users/CMakeLists.txt
@@ -1,9 +1,4 @@
-find_package(ECM ${ECM_VERSION} NO_MODULE)
-if( ECM_FOUND )
- include( ECMAddTests )
-endif()
-
-find_package( Qt5 COMPONENTS Core Test REQUIRED )
+find_package( Qt5 COMPONENTS Core REQUIRED )
find_package( Crypt REQUIRED )
# Add optional libraries here
@@ -44,7 +39,7 @@ calamares_add_plugin( users
SHARED_LIB
)
-if( ECM_FOUND )
+if( ECM_FOUND AND BUILD_TESTING )
ecm_add_test(
PasswordTests.cpp
SetPasswordJob.cpp