diff --git a/CHANGES b/CHANGES index c7e5432ce..7094f5866 100644 --- a/CHANGES +++ b/CHANGES @@ -10,15 +10,31 @@ This release contains contributions from (alphabetically by first name): - 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. 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/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. 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. - 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 @@ The <strong>boot environment</strong> of this system.<br><br>Older x86 systems only support <strong>BIOS</strong>.<br>Modern systems usually use <strong>EFI</strong>, but may also show up as BIOS if started in compatibility mode. - 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. Contextual Processes Job - + משימת תהליכי הקשר @@ -2358,7 +2358,7 @@ Output: Shell Processes Job - + משימת תהליכי מעטפת 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 @@ &Install - + &Telepítés @@ -229,7 +229,7 @@ Minden változtatás elveszik, ha kilépsz a telepítőből. &No - @Nem + &Nem @@ -944,7 +944,7 @@ Telepítés nem folytatható. <a href="#details">Részletek...&l &Restart now - $Ú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. The %1 installer is about to make changes to your disk in order to install %2.<br/><strong>You will not be able to undo these changes.</strong> - %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 @@ Blank Page - + Lege pagina @@ -192,7 +192,7 @@ Calamares Initialization Failed - + Calamares Initialisatie mislukt @@ -202,7 +202,7 @@ <br/>The following modules could not be loaded: - + <br/>The volgende modules konden niet worden geladen: @@ -1244,7 +1244,7 @@ Het installatieprogramma zal afsluiten en alle wijzigingen zullen verloren gaan. Password is too weak - + Wachtwoord is te zwak @@ -1259,12 +1259,12 @@ Het installatieprogramma zal afsluiten en alle wijzigingen zullen verloren gaan. The password is the same as the old one - + Het wachtwoord is hetzelfde als het oude wachtwoord The password is a palindrome - + Het wachtwoord is een palindroom @@ -1274,12 +1274,12 @@ Het installatieprogramma zal afsluiten en alle wijzigingen zullen verloren gaan. The password is too similar to the old one - + Het wachtwoord lijkt te veel op het oude wachtwoord The password contains the user name in some form - + 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 @@ This system was started with an <strong>EFI</strong> boot environment.<br><br>To configure startup from an EFI environment, this installer must deploy a boot loader application, like <strong>GRUB</strong> or <strong>systemd-boot</strong> on an <strong>EFI System Partition</strong>. This is automatic, unless you choose manual partitioning, in which case you must choose it or create it on your own. - 这个系统从 <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 @@ Blank Page - + 空白页 @@ -193,17 +193,17 @@ Calamares Initialization Failed - + Calamares安装失败 %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. - + %1无法安装。 Calamares无法加载所有已配置的模块。这是分配使用Calamares的方式的问题。 <br/>The following modules could not be loaded: - + <br/>无法加载以下模块: @@ -265,7 +265,7 @@ The installer will quit and all changes will be lost. The installation is complete. Close the installer. - 安装过程已完毕。请关闭安装器。 + 安装已完成。请关闭安装程序。 @@ -334,7 +334,7 @@ The installer will quit and all changes will be lost. For best results, please ensure that this computer: - 为了更好的体验,请确定这台电脑: + 为了更好的体验,请确保这台电脑: @@ -509,12 +509,12 @@ The installer will quit and all changes will be lost. The command runs in the host environment and needs to know the root path, but no rootMountPoint is defined. - + 该命令在主机环境中运行,且需要知道根路径,但没有定义root挂载点。 The command needs to know the user's name, but no username is defined. - + 命令行需要知道用户的名字,但用户名没有被设置 @@ -1665,7 +1665,7 @@ The installer will quit and all changes will be lost. Cre&ate - + 创建 @@ -1690,12 +1690,12 @@ The installer will quit and all changes will be lost. Can not create new partition - + 无法创建新分区 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. - + %1上的分区表已经有%2个主分区,并且不能再添加。请删除一个主分区并添加扩展分区。 @@ -1841,17 +1841,17 @@ The installer will quit and all changes will be lost. Saving files for later ... - + 保存文件以供日后使用 No files configured to save for later. - + 没有已保存且供日后使用的配置文件。 Not all of the configured files could be preserved. - + 并不是所有配置文件都可以被保留 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/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 a1349c280..ef629ac4d 100644 --- a/src/libcalamaresui/modulesystem/Module.cpp +++ b/src/libcalamaresui/modulesystem/Module.cpp @@ -155,6 +155,10 @@ moduleConfigurationCandidates( bool assumeBuildDir, const QString& moduleName, c 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 ) ); } 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 index 5de329cad..e339b2799 100644 --- a/src/modules/fsresizer/CMakeLists.txt +++ b/src/modules/fsresizer/CMakeLists.txt @@ -20,10 +20,7 @@ if ( KPMcore_FOUND ) 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/fsresizer/ResizeFSJob.cpp b/src/modules/fsresizer/ResizeFSJob.cpp index 0589e1866..4df41a7d4 100644 --- a/src/modules/fsresizer/ResizeFSJob.cpp +++ b/src/modules/fsresizer/ResizeFSJob.cpp @@ -33,6 +33,7 @@ #include "JobQueue.h" #include "GlobalStorage.h" +#include "utils/CalamaresUtils.h" #include "utils/Logger.h" #include "utils/Units.h" @@ -48,11 +49,11 @@ ResizeFSJob::RelativeSize::RelativeSize() template void matchUnitSuffix( const QString& s, - const char (&suffix)[N], + const char ( &suffix )[N], ResizeFSJob::RelativeSize::Unit matchedUnit, int& value, ResizeFSJob::RelativeSize::Unit& unit - ) +) { if ( s.endsWith( suffix ) ) { @@ -62,13 +63,13 @@ void matchUnitSuffix( } -ResizeFSJob::RelativeSize::RelativeSize( const QString& s) +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."; @@ -81,14 +82,14 @@ ResizeFSJob::RelativeSize::RelativeSize( const QString& s) } qint64 -ResizeFSJob::RelativeSize::apply( qint64 totalSectors , qint64 sectorSize ) +ResizeFSJob::RelativeSize::apply( qint64 totalSectors, qint64 sectorSize ) { if ( !isValid() ) return -1; if ( sectorSize < 1 ) return -1; - - switch( m_unit ) + + switch ( m_unit ) { case None: return -1; @@ -113,6 +114,7 @@ ResizeFSJob::RelativeSize::apply( Device* d ) ResizeFSJob::ResizeFSJob( QObject* parent ) : Calamares::CppJob( parent ) + , m_required( false ) { } @@ -136,14 +138,14 @@ ResizeFSJob::findPartition( CoreBackend* backend ) cDebug() << "ResizeFSJob found" << devices.count() << "devices."; for ( DeviceList::iterator dev_it = devices.begin(); dev_it != devices.end(); ++dev_it ) { - if ( ! (*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 ) ) + ( !m_devicename.isEmpty() && ( *part_it )->deviceNode() == m_devicename ) ) { cDebug() << ".. matched configuration dev=" << m_devicename << "fs=" << m_fsname; return PartitionMatch( *dev_it, *part_it ); @@ -156,7 +158,7 @@ ResizeFSJob::findPartition( CoreBackend* backend ) } /** @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 @@ -164,7 +166,7 @@ ResizeFSJob::findPartition( CoreBackend* backend ) * by occupied space after it). */ qint64 -ResizeFSJob::findGrownEnd(ResizeFSJob::PartitionMatch m) +ResizeFSJob::findGrownEnd( ResizeFSJob::PartitionMatch m ) { if ( !m.first || !m.second ) return -1; // Missing device data @@ -193,7 +195,7 @@ ResizeFSJob::findGrownEnd(ResizeFSJob::PartitionMatch m) continue; } cDebug() << ".. comparing" << next_start << '-' << next_end; - if ( (next_start > last_currently) && (next_start < last_available) ) + 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 @@ -202,7 +204,7 @@ ResizeFSJob::findGrownEnd(ResizeFSJob::PartitionMatch m) if ( !( last_available > last_currently ) ) { - cDebug() << "Partition can not grow larger."; + cDebug() << "Partition cannot grow larger."; return 0; } @@ -223,7 +225,7 @@ ResizeFSJob::findGrownEnd(ResizeFSJob::PartitionMatch m) cDebug() << ".. only growing by" << wanted << "instead of full" << expand; last_available -= ( expand - wanted ); } - + return last_available; } @@ -234,13 +236,12 @@ 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." ) ); + 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(); + cDebug() << "KPMCore backend @" << ( void* )backend_p << backend_p->id() << backend_p->version(); else { cDebug() << "No KPMCore backend loaded yet"; @@ -269,8 +270,8 @@ ResizeFSJob::exec() 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 can not be resized." ).arg(m_fsname) - : tr( "The device %1 could not be found in this system, and can not be resized." ).arg(m_devicename) ); + !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 ) ) @@ -278,29 +279,34 @@ ResizeFSJob::exec() cDebug() << "canGrow() returned false."; return Calamares::JobResult::error( tr( "Resize Failed" ), - !m_fsname.isEmpty() ? tr( "The filesystem %1 can not be resized." ).arg(m_fsname) - : tr( "The device %1 can not be resized." ).arg(m_devicename) ); + !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; + << 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 can not be resized." ).arg(m_fsname) - : tr( "The device %1 can not be resized." ).arg(m_devicename) ); + !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 ) { - // TODO: is that a bad thing? is the resize required? cWarning() << "Resize operation on" << m_fsname << m_devicename - << "skipped as not-useful."; + << "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 ); @@ -311,8 +317,8 @@ ResizeFSJob::exec() { cDebug() << "Resize failed." << op_report.output(); return Calamares::JobResult::error( - tr( "Resize Failed" ), - op_report.toText() ); + tr( "Resize Failed" ), + op_report.toText() ); } } @@ -334,6 +340,8 @@ ResizeFSJob::setConfigurationMap( const QVariantMap& configurationMap ) 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 index 063495e7d..c34ccb865 100644 --- a/src/modules/fsresizer/ResizeFSJob.h +++ b/src/modules/fsresizer/ResizeFSJob.h @@ -68,19 +68,19 @@ public: * * 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; @@ -107,6 +107,7 @@ private: 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 */ diff --git a/src/modules/fsresizer/fsresizer.conf b/src/modules/fsresizer/fsresizer.conf index 06141fc7d..33329248d 100644 --- a/src/modules/fsresizer/fsresizer.conf +++ b/src/modules/fsresizer/fsresizer.conf @@ -12,7 +12,7 @@ # 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 +# - *dev* names a device fs: / # dev: /dev/mmcblk0p1 @@ -33,5 +33,17 @@ size: 100% # 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 +#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/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/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 b8011f066..f41142b6a 100644 --- a/src/modules/partition/core/PartitionCoreModule.cpp +++ b/src/modules/partition/core/PartitionCoreModule.cpp @@ -509,17 +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:" - << jobsDebug.join( "\n" ); - return lst; } diff --git a/src/modules/partition/gui/ChoicePage.cpp b/src/modules/partition/gui/ChoicePage.cpp index 3f0e5a72a..5b1577369 100644 --- a/src/modules/partition/gui/ChoicePage.cpp +++ b/src/modules/partition/gui/ChoicePage.cpp @@ -1209,6 +1209,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 @@ -1222,6 +1229,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 @@ -1238,18 +1248,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 ) @@ -1366,7 +1388,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 2aec4a5fc..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,21 +83,28 @@ CreatePartitionTableJob::exec() PartitionTable* table = m_device->partitionTable(); cDebug() << "Creating new partition table of type" << table->typeName() - << ", uncommitted yet:\n" << table; + << ", uncommitted yet:"; - QProcess lsblk; - lsblk.setProgram( "lsblk" ); - lsblk.setProcessChannelMode( QProcess::MergedChannels ); - lsblk.start(); - lsblk.waitForFinished(); - cDebug() << "lsblk:\n" << lsblk.readAllStandardOutput(); + if ( Logger::logLevelEnabled( Logger::LOGDEBUG ) ) + { + for ( auto it = PartitionIterator::begin( table ); + it != PartitionIterator::end( table ); ++it ) + cDebug() << *it; - QProcess mount; - mount.setProgram( "mount" ); - mount.setProcessChannelMode( QProcess::MergedChannels ); - mount.start(); - mount.waitForFinished(); - cDebug() << "mount:\n" << mount.readAllStandardOutput(); + QProcess lsblk; + lsblk.setProgram( "lsblk" ); + lsblk.setProcessChannelMode( QProcess::MergedChannels ); + lsblk.start(); + lsblk.waitForFinished(); + cDebug() << "lsblk:\n" << lsblk.readAllStandardOutput(); + + 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/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