diff --git a/.gitattributes b/.gitattributes index d7a0364e1..3b8a7f1e8 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,6 +1,11 @@ -.tx/* export-ignore -hacking/* export-ignore -HACKING.md export-ignore -.editorconfig export-ignore -src/modules/testmodule.py export-ignore +.editorconfig export-ignore +.gitattributes export-ignore +.github export-ignore +.gitignore export-ignore +.gitmodules export-ignore +.travis.yml export-ignore +.tx export-ignore + +src/modules/testmodule.py export-ignore src/modules/globalStorage.yaml export-ignore + diff --git a/CHANGES b/CHANGES index 56526aad2..c7e5432ce 100644 --- a/CHANGES +++ b/CHANGES @@ -6,11 +6,23 @@ website will have to do for older versions. # 3.2.3 (unreleased) # This release contains contributions from (alphabetically by first name): + - Alf Gaida + - Caio Carvalho + - Kevin Kofler + - Philip Mueller ## Core ## ## Modules ## + * The *partition* module supports RAID devices, but only when Calamares + is compiled with the newest KPMCore release. + * The *keyboard* module now handles the (bogus) Austrian keymap for + the system console properly. + * 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) # This release contains contributions from (alphabetically by first name): diff --git a/CMakeModules/CalamaresAddBrandingSubdirectory.cmake b/CMakeModules/CalamaresAddBrandingSubdirectory.cmake index f4eb349f2..78330e245 100644 --- a/CMakeModules/CalamaresAddBrandingSubdirectory.cmake +++ b/CMakeModules/CalamaresAddBrandingSubdirectory.cmake @@ -79,10 +79,8 @@ function( calamares_add_branding NAME ) endforeach() message( "-- ${BoldYellow}Found ${CALAMARES_APPLICATION_NAME} branding component: ${BoldRed}${NAME}${ColorReset}" ) - if( NOT CMAKE_BUILD_TYPE STREQUAL "Release" ) - message( " ${Green}TYPE:${ColorReset} branding component" ) - message( " ${Green}BRANDING_COMPONENT_DESTINATION:${ColorReset} ${BRANDING_COMPONENT_DESTINATION}" ) - endif() + message( " ${Green}TYPE:${ColorReset} branding component" ) + message( " ${Green}BRANDING_COMPONENT_DESTINATION:${ColorReset} ${BRANDING_COMPONENT_DESTINATION}" ) endfunction() # Usage calamares_add_branding_translations( [DIRECTORY ]) diff --git a/CMakeModules/CalamaresAddModuleSubdirectory.cmake b/CMakeModules/CalamaresAddModuleSubdirectory.cmake index 0b417bdf3..74ff640d9 100644 --- a/CMakeModules/CalamaresAddModuleSubdirectory.cmake +++ b/CMakeModules/CalamaresAddModuleSubdirectory.cmake @@ -99,19 +99,17 @@ function( calamares_add_module_subdirectory ) endforeach() message( "-- ${BoldYellow}Found ${CALAMARES_APPLICATION_NAME} module: ${BoldRed}${SUBDIRECTORY}${ColorReset}" ) - if( NOT CMAKE_BUILD_TYPE STREQUAL "Release" ) - message( " ${Green}TYPE:${ColorReset} jobmodule" ) - message( " ${Green}MODULE_DESTINATION:${ColorReset} ${MODULE_DESTINATION}" ) - if( MODULE_CONFIG_FILES ) - if ( INSTALL_CONFIG ) - set( _destination "${MODULE_DATA_DESTINATION}" ) - else() - set( _destination "[Build directory only]" ) - endif() - message( " ${Green}CONFIGURATION_FILES:${ColorReset} ${MODULE_CONFIG_FILES} => ${_destination}" ) + message( " ${Green}TYPE:${ColorReset} jobmodule" ) + message( " ${Green}MODULE_DESTINATION:${ColorReset} ${MODULE_DESTINATION}" ) + if( MODULE_CONFIG_FILES ) + if ( INSTALL_CONFIG ) + set( _destination "${MODULE_DATA_DESTINATION}" ) + else() + set( _destination "[Build directory only]" ) endif() - message( "" ) + message( " ${Green}CONFIGURATION_FILES:${ColorReset} ${MODULE_CONFIG_FILES} => ${_destination}" ) endif() + message( "" ) # We copy over the lang directory, if any if( IS_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/${SUBDIRECTORY}/lang" ) install_calamares_gettext_translations( diff --git a/CMakeModules/CalamaresAddPlugin.cmake b/CMakeModules/CalamaresAddPlugin.cmake index 1bf20e4ca..886501a56 100644 --- a/CMakeModules/CalamaresAddPlugin.cmake +++ b/CMakeModules/CalamaresAddPlugin.cmake @@ -62,28 +62,27 @@ function( calamares_add_plugin ) set( CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}" ) message( "-- ${BoldYellow}Found ${CALAMARES_APPLICATION_NAME} module: ${BoldRed}${PLUGIN_NAME}${ColorReset}" ) - if( NOT CMAKE_BUILD_TYPE STREQUAL "Release" ) - message( " ${Green}TYPE:${ColorReset} ${PLUGIN_TYPE}" ) - message( " ${Green}LINK_LIBRARIES:${ColorReset} ${PLUGIN_LINK_LIBRARIES}" ) - message( " ${Green}LINK_PRIVATE_LIBRARIES:${ColorReset} ${PLUGIN_LINK_PRIVATE_LIBRARIES}" ) - message( " ${Green}PLUGIN_DESTINATION:${ColorReset} ${PLUGIN_DESTINATION}" ) - if( PLUGIN_CONFIG_FILES ) - set( _destination "(unknown)" ) - if ( INSTALL_CONFIG AND NOT PLUGIN_NO_INSTALL ) - set( _destination "${PLUGIN_DATA_DESTINATION}" ) - elseif( NOT PLUGIN_NO_INSTALL ) - # Not INSTALL_CONFIG - set( _destination "[Build directory only]" ) - else() - set( _destination "[Skipping installation]" ) - endif() - message( " ${Green}CONFIGURATION_FILES:${ColorReset} ${PLUGIN_CONFIG_FILES} => ${_destination}" ) + message( " ${Green}TYPE:${ColorReset} ${PLUGIN_TYPE}" ) + message( " ${Green}LINK_LIBRARIES:${ColorReset} ${PLUGIN_LINK_LIBRARIES}" ) + message( " ${Green}LINK_PRIVATE_LIBRARIES:${ColorReset} ${PLUGIN_LINK_PRIVATE_LIBRARIES}" ) + message( " ${Green}PLUGIN_DESTINATION:${ColorReset} ${PLUGIN_DESTINATION}" ) + if( PLUGIN_CONFIG_FILES ) + set( _destination "(unknown)" ) + if ( INSTALL_CONFIG AND NOT PLUGIN_NO_INSTALL ) + set( _destination "${PLUGIN_DATA_DESTINATION}" ) + elseif( NOT PLUGIN_NO_INSTALL ) + # Not INSTALL_CONFIG + set( _destination "[Build directory only]" ) + else() + set( _destination "[Skipping installation]" ) endif() - if( PLUGIN_RESOURCES ) - message( " ${Green}RESOURCES:${ColorReset} ${PLUGIN_RESOURCES}" ) - endif() - message( "" ) + message( " ${Green}CONFIGURATION_FILES:${ColorReset} ${PLUGIN_CONFIG_FILES} => ${_destination}" ) endif() + if( PLUGIN_RESOURCES ) + message( " ${Green}RESOURCES:${ColorReset} ${PLUGIN_RESOURCES}" ) + endif() + message( "" ) + # create target name once for convenience set( target "calamares_${PLUGIN_TYPE}_${PLUGIN_NAME}" ) diff --git a/calamares.desktop b/calamares.desktop index 5b73cecf3..3cdce6888 100644 --- a/calamares.desktop +++ b/calamares.desktop @@ -21,7 +21,7 @@ Name[be]=Усталяваць сістэму Icon[bg]=calamares GenericName[bg]=Системен Инсталатор Comment[bg]=Calamares — Системен Инсталатор -Name[bg]=Инсталирай система +Name[bg]=Инсталирай системата Icon[ca]=calamares GenericName[ca]=Instal·lador de sistema Comment[ca]=Calamares — Instal·lador de sistema 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_bg.ts b/lang/calamares_bg.ts index f9dc45c36..d75f03746 100644 --- a/lang/calamares_bg.ts +++ b/lang/calamares_bg.ts @@ -50,7 +50,7 @@ Blank Page - + Празна страница @@ -192,22 +192,22 @@ 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/>Следните модули не могат да се заредят: &Install - + &Инсталирай @@ -287,17 +287,17 @@ The installer will quit and all changes will be lost. unparseable Python error - неанализируема Python грешка + неанализируема грешка на Python unparseable Python traceback - неанализируемо Python проследяване + неанализируемо проследяване на Python Unfetchable Python error. - Недостъпна Python грешка. + Недостъпна грешка на Python. @@ -504,17 +504,17 @@ The installer will quit and all changes will be lost. Could not run command. - + Командата не може да се изпълни. The command runs in the host environment and needs to know the root path, but no rootMountPoint is defined. - + Командата се изпълнява в средата на хоста и трябва да установи местоположението на основния дял, но rootMountPoint не е определен. The command needs to know the user's name, but no username is defined. - + Командата трябва да установи потребителското име на профила, но такова не е определено. @@ -522,7 +522,7 @@ The installer will quit and all changes will be lost. Contextual Processes Job - + Задача с контекстуални процеси @@ -580,7 +580,7 @@ The installer will quit and all changes will be lost. En&crypt - En%crypt + Ши&фриране @@ -784,12 +784,12 @@ The installer will quit and all changes will be lost. Write LUKS configuration for Dracut to %1 - + Запиши LUKS конфигурация за Dracut на %1 Skip writing LUKS configuration for Dracut: "/" partition is not encrypted - + Пропусни записването на LUKS конфигурация за Dracut: "/" дял не е шифриран @@ -939,7 +939,7 @@ The installer will quit and all changes will be lost. <html><head/><body><p>When this box is checked, your system will restart immediately when you click on <span style=" font-style:italic;">Done</span> or close the installer.</p></body></html> - + <html><head/><body><p>Когато тази опция е избрана, Вашата система ще се рестартира незабавно при натискане на <span style=" font-style:italic;">Готово</span> или при затваряне на инсталатора.</p></body></html> @@ -954,7 +954,7 @@ The installer will quit and all changes will be lost. <h1>Installation Failed</h1><br/>%1 has not been installed on your computer.<br/>The error message was: %2. - + <h1>Инсталацията е неуспешна</h1><br/>%1 не е инсталиран на Вашия компютър.<br/>Съобщението с грешката е: %2. @@ -967,12 +967,12 @@ The installer will quit and all changes will be lost. Installation Complete - + Инсталацията е завършена The installation of %1 is complete. - + Инсталацията на %1 е завършена. @@ -1156,7 +1156,7 @@ The installer will quit and all changes will be lost. The numbers and dates locale will be set to %1. - + Форматът на цифрите и датата ще бъде %1. @@ -1214,12 +1214,12 @@ The installer will quit and all changes will be lost. Network Installation. (Disabled: Unable to fetch package lists, check your network connection) - + Мрежова инсталация. (Изключена: Списъкът с пакети не може да бъде извлечен, проверете Вашата Интернет връзка) Network Installation. (Disabled: Received invalid groups data) - + Мрежова инсталация. (Изключена: Получени са данни за невалидни групи) @@ -1250,12 +1250,12 @@ The installer will quit and all changes will be lost. Memory allocation error when setting '%1' - + Грешка при разпределяне на паметта по време на настройването на '%1' Memory allocation error - + Грешка при разпределяне на паметта @@ -1270,7 +1270,7 @@ The installer will quit and all changes will be lost. The password differs with case changes only - + Паролата се различава само със смяна на главни и малки букви @@ -1280,62 +1280,62 @@ The installer will quit and all changes will be lost. The password contains the user name in some form - + Паролата съдържа потребителското име под някаква форма The password contains words from the real name of the user in some form - + Паролата съдържа думи от истинското име на потребителя под някаква форма The password contains forbidden words in some form - + Паролата съдържа забранени думи под някаква форма The password contains less than %1 digits - + Паролата съдържа по-малко от %1 цифри The password contains too few digits - + Паролата съдържа твърде малко цифри The password contains less than %1 uppercase letters - + Паролата съдържа по-малко от %1 главни букви The password contains too few uppercase letters - + Паролата съдържа твърде малко главни букви The password contains less than %1 lowercase letters - + Паролата съдържа по-малко от %1 малки букви The password contains too few lowercase letters - + Паролата съдържа твърде малко малки букви The password contains less than %1 non-alphanumeric characters - + Паролата съдържа по-малко от %1 знаци, които не са букви или цифри The password contains too few non-alphanumeric characters - + Паролата съдържа твърде малко знаци, които не са букви или цифри The password is shorter than %1 characters - + Паролата е по-малка от %1 знаци @@ -1345,47 +1345,47 @@ The installer will quit and all changes will be lost. The password is just rotated old one - + Паролата е обърнат вариант на старата The password contains less than %1 character classes - + Паролата съдържа по-малко от %1 видове знаци The password does not contain enough character classes - + Паролата не съдържа достатъчно видове знаци The password contains more than %1 same characters consecutively - + Паролата съдържа повече от %1 еднакви знаци последователно The password contains too many same characters consecutively - + Паролата съдържа твърде много еднакви знаци последователно The password contains more than %1 characters of the same class consecutively - + Паролата съдържа повече от %1 еднакви видове знаци последователно The password contains too many characters of the same class consecutively - + Паролата съдържа твърде много еднакви видове знаци последователно The password contains monotonic sequence longer than %1 characters - + Паролата съдържа монотонна последователност, по-дълга от %1 знаци The password contains too long of a monotonic character sequence - + Паролата съдържа твърде дълга монотонна последователност от знаци @@ -1395,77 +1395,77 @@ The installer will quit and all changes will be lost. Cannot obtain random numbers from the RNG device - + Получаването на произволни числа от RNG устройството е неуспешно Password generation failed - required entropy too low for settings - + Генерирането на парола е неуспешно - необходимата ентропия е твърде ниска за настройки The password fails the dictionary check - %1 - + Паролата не издържа проверката на речника - %1 The password fails the dictionary check - + Паролата не издържа проверката на речника Unknown setting - %1 - + Неизвестна настройка - %1 Unknown setting - + Неизвестна настройка Bad integer value of setting - %1 - + Невалидна числена стойност на настройката - %1 Bad integer value - + Невалидна числена стойност на настройката Setting %1 is not of integer type - + Настройката %1 не е от числов вид Setting is not of integer type - + Настройката не е от числов вид Setting %1 is not of string type - + Настройката %1 не е от текстов вид Setting is not of string type - + Настройката не е от текстов вид Opening the configuration file failed - + Отварянето на файла с конфигурацията е неуспешно The configuration file is malformed - + Файлът с конфигурацията е деформиран Fatal failure - + Фатална повреда @@ -1664,7 +1664,7 @@ The installer will quit and all changes will be lost. Cre&ate - + Съз&дай @@ -1689,12 +1689,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 главни дялове, повече не може да се добавят. Моля, премахнете един главен дял и добавете разширен дял, на негово място. @@ -1787,7 +1787,7 @@ The installer will quit and all changes will be lost. Boot partition not encrypted - + Липсва криптиране на дял за начално зареждане @@ -1819,7 +1819,7 @@ The installer will quit and all changes will be lost. Placeholder - + Заместител @@ -1866,7 +1866,9 @@ There was no output from the command. Output: - + +Резултат: + @@ -2088,7 +2090,7 @@ Output: The screen is too small to display the installer. - + Екранът е твърде малък за инсталатора. @@ -2290,7 +2292,7 @@ Output: rootMountPoint is %1 - root точка на монтиране е %1 + rootMountPoint е %1 @@ -2328,7 +2330,7 @@ Output: Bad path: %1 - Лош път: %1 + Невалиден път: %1 @@ -2365,7 +2367,7 @@ Output: %L1 / %L2 slide counter, %1 of %2 (numeric) - + %L1 / %L2 @@ -2446,7 +2448,7 @@ Output: Placeholder - + Заместител @@ -2458,7 +2460,7 @@ Output: TextLabel - + TextLabel @@ -2498,7 +2500,7 @@ Output: Feedback - + Обратна връзка @@ -2583,7 +2585,7 @@ Output: <h1>Welcome to the Calamares installer for %1.</h1> - + <h1>Добре дошли при инсталатора Calamares на %1.</h1> @@ -2593,7 +2595,7 @@ Output: <h1>%1</h1><br/><strong>%2<br/>for %3</strong><br/><br/>Copyright 2014-2017 Teo Mrnjavac &lt;teo@kde.org&gt;<br/>Copyright 2017 Adriaan de Groot &lt;groot@kde.org&gt;<br/>Thanks to: Anke Boersma, Aurélien Gâteau, Kevin Kofler, Lisa Vitolo, Philip Müller, Pier Luigi Fiorini, Rohan Garg and the <a href="https://www.transifex.com/calamares/calamares/">Calamares translators team</a>.<br/><br/><a href="https://calamares.io/">Calamares</a> development is sponsored by <br/><a href="http://www.blue-systems.com/">Blue Systems</a> - Liberating Software. - + <h1>%1</h1><br/><strong>%2<br/>за %3</strong><br/><br/>Авторско право 2014-2017 Teo Mrnjavac &lt;teo@kde.org&gt;<br/>Авторско право 2017 Adriaan de Groot &lt;groot@kde.org&gt;<br/>Благодарности към: Anke Boersma, Aurélien Gâteau, Kevin Kofler, Lisa Vitolo, Philip Müller, Pier Luigi Fiorini, Rohan Garg и <a href="https://www.transifex.com/calamares/calamares/">преводачите на Calamares</a>.<br/><br/>Разработката на <a href="https://calamares.io/">Calamares</a> е спонсорирана от <br/><a href="http://www.blue-systems.com/">Blue Systems</a> - Liberating Software. diff --git a/lang/calamares_id.ts b/lang/calamares_id.ts index 194f9f004..5dfe06b9e 100644 --- a/lang/calamares_id.ts +++ b/lang/calamares_id.ts @@ -50,7 +50,7 @@ Blank Page - + Halaman Kosong @@ -192,17 +192,17 @@ Calamares Initialization Failed - + Inisialisasi Calamares Gagal %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 tidak dapat terpasang. Calamares tidak dapat memuat seluruh modul konfigurasi. Terdapat masalah dengan Calamares karena sedang digunakan oleh distribusi. <br/>The following modules could not be loaded: - + <br/>Modul berikut tidak dapat dimuat. @@ -1665,7 +1665,7 @@ Pemasangan dapat dilanjutkan, namun beberapa fitur akan dinonfungsikan. Cre&ate - + Mem&buat diff --git a/lang/calamares_tr_TR.ts b/lang/calamares_tr_TR.ts index 11476558b..7acd733f0 100644 --- a/lang/calamares_tr_TR.ts +++ b/lang/calamares_tr_TR.ts @@ -1696,7 +1696,7 @@ Kuruluma devam edebilirsiniz fakat bazı özellikler devre dışı kalabilir. 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 üzerindeki bölüm tablosu zaten% 2 birincil bölüme sahip ve artık eklenemiyor. Lütfen bir birincil bölümü kaldırın ve bunun yerine genişletilmiş bir bölüm ekleyin. + %1 üzerindeki disk bölümü tablosu zaten %2 birincil disk bölümüne sahip ve artık eklenemiyor. Lütfen bir birincil disk bölümü kaldırın ve bunun yerine uzatılmış bir disk bölümü ekleyin. diff --git a/lang/python/bg/LC_MESSAGES/python.mo b/lang/python/bg/LC_MESSAGES/python.mo index f646fe6c3..3198676e1 100644 Binary files a/lang/python/bg/LC_MESSAGES/python.mo and b/lang/python/bg/LC_MESSAGES/python.mo differ diff --git a/lang/python/bg/LC_MESSAGES/python.po b/lang/python/bg/LC_MESSAGES/python.po index 310613b29..8f675fad1 100644 --- a/lang/python/bg/LC_MESSAGES/python.po +++ b/lang/python/bg/LC_MESSAGES/python.po @@ -20,24 +20,24 @@ msgstr "" #: src/modules/umount/main.py:40 msgid "Unmount file systems." -msgstr "" +msgstr "Демонтирай файловите системи." #: src/modules/dummypython/main.py:44 msgid "Dummy python job." -msgstr "" +msgstr "Фиктивна задача python." #: src/modules/dummypython/main.py:97 msgid "Dummy python step {}" -msgstr "" +msgstr "Фиктивна стъпка на python {}" #: src/modules/machineid/main.py:35 msgid "Generate machine-id." -msgstr "" +msgstr "Генерирай machine-id." #: src/modules/packages/main.py:62 #, python-format msgid "Processing packages (%(count)d / %(total)d)" -msgstr "" +msgstr "Обработване на пакетите (%(count)d / %(total)d)" #: src/modules/packages/main.py:64 src/modules/packages/main.py:74 msgid "Install packages." diff --git a/lang/python/tr_TR/LC_MESSAGES/python.mo b/lang/python/tr_TR/LC_MESSAGES/python.mo index 76f5d0bc7..50fc52cad 100644 Binary files a/lang/python/tr_TR/LC_MESSAGES/python.mo and b/lang/python/tr_TR/LC_MESSAGES/python.mo differ diff --git a/lang/python/tr_TR/LC_MESSAGES/python.po b/lang/python/tr_TR/LC_MESSAGES/python.po index cfcb8b328..4b2baad96 100644 --- a/lang/python/tr_TR/LC_MESSAGES/python.po +++ b/lang/python/tr_TR/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: Demiray “tulliana” Muhterem , 2017\n" +"Last-Translator: Demiray Muhterem , 2017\n" "Language-Team: Turkish (Turkey) (https://www.transifex.com/calamares/teams/20061/tr_TR/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" 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/libcalamaresui/ViewManager.cpp b/src/libcalamaresui/ViewManager.cpp index 2b9f87db8..4d1f3591e 100644 --- a/src/libcalamaresui/ViewManager.cpp +++ b/src/libcalamaresui/ViewManager.cpp @@ -191,7 +191,7 @@ ViewManager::onInitFailed( const QStringList& modules) detailString = details.join( QString() ); } - insertViewStep( 0, new BlankViewStep( title, description.arg( *Calamares::Branding::ShortProductName ), detailString ) ); + insertViewStep( 0, new BlankViewStep( title, description.arg( *Calamares::Branding::ProductName ), detailString ) ); } ViewStepList diff --git a/src/libcalamaresui/modulesystem/Module.cpp b/src/libcalamaresui/modulesystem/Module.cpp index 8d92c37ad..a1349c280 100644 --- a/src/libcalamaresui/modulesystem/Module.cpp +++ b/src/libcalamaresui/modulesystem/Module.cpp @@ -145,8 +145,15 @@ 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 ); paths << QString( "/etc/calamares/modules/%1" ).arg( configFileName ); paths << CalamaresUtils::appDataDir().absoluteFilePath( QString( "modules/%1" ).arg( configFileName ) ); @@ -168,6 +175,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 +186,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/dummypythonqt/lang/bg/LC_MESSAGES/dummypythonqt.mo b/src/modules/dummypythonqt/lang/bg/LC_MESSAGES/dummypythonqt.mo index 348cc2629..a0e186582 100644 Binary files a/src/modules/dummypythonqt/lang/bg/LC_MESSAGES/dummypythonqt.mo and b/src/modules/dummypythonqt/lang/bg/LC_MESSAGES/dummypythonqt.mo differ diff --git a/src/modules/dummypythonqt/lang/bg/LC_MESSAGES/dummypythonqt.po b/src/modules/dummypythonqt/lang/bg/LC_MESSAGES/dummypythonqt.po index 011a2294f..9a404c31a 100644 --- a/src/modules/dummypythonqt/lang/bg/LC_MESSAGES/dummypythonqt.po +++ b/src/modules/dummypythonqt/lang/bg/LC_MESSAGES/dummypythonqt.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2018-02-07 18:58+0100\n" +"POT-Creation-Date: 2018-06-18 07:46-0400\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: Georgi Georgiev , 2018\n" "Language-Team: Bulgarian (https://www.transifex.com/calamares/teams/20061/bg/)\n" @@ -28,16 +28,16 @@ msgstr "Нов QLabel." #: src/modules/dummypythonqt/main.py:97 msgid "Dummy PythonQt ViewStep" -msgstr "" +msgstr "Фиктивен PythonQt ViewStep" #: src/modules/dummypythonqt/main.py:183 msgid "The Dummy PythonQt Job" -msgstr "" +msgstr "Фиктивната задача PythonQt" #: src/modules/dummypythonqt/main.py:186 msgid "This is the Dummy PythonQt Job. The dummy job says: {}" -msgstr "" +msgstr "Това е фиктивната задача PythonQt. Фиктивната задача заявява: {}" #: src/modules/dummypythonqt/main.py:190 msgid "A status message for Dummy PythonQt Job." -msgstr "" +msgstr "Съобщение за състоянието на фиктивната задача PythonQt." diff --git a/src/modules/dummypythonqt/lang/tr_TR/LC_MESSAGES/dummypythonqt.mo b/src/modules/dummypythonqt/lang/tr_TR/LC_MESSAGES/dummypythonqt.mo index 57e8ac336..6d0fa2168 100644 Binary files a/src/modules/dummypythonqt/lang/tr_TR/LC_MESSAGES/dummypythonqt.mo and b/src/modules/dummypythonqt/lang/tr_TR/LC_MESSAGES/dummypythonqt.mo differ diff --git a/src/modules/dummypythonqt/lang/tr_TR/LC_MESSAGES/dummypythonqt.po b/src/modules/dummypythonqt/lang/tr_TR/LC_MESSAGES/dummypythonqt.po index cf65fd0e5..19fd56b06 100644 --- a/src/modules/dummypythonqt/lang/tr_TR/LC_MESSAGES/dummypythonqt.po +++ b/src/modules/dummypythonqt/lang/tr_TR/LC_MESSAGES/dummypythonqt.po @@ -8,9 +8,9 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2018-02-07 18:58+0100\n" +"POT-Creation-Date: 2018-06-18 07:46-0400\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" -"Last-Translator: Demiray “tulliana” Muhterem , 2016\n" +"Last-Translator: Demiray Muhterem , 2016\n" "Language-Team: Turkish (Turkey) (https://www.transifex.com/calamares/teams/20061/tr_TR/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" diff --git a/src/modules/fsresizer/CMakeLists.txt b/src/modules/fsresizer/CMakeLists.txt new file mode 100644 index 000000000..5de329cad --- /dev/null +++ b/src/modules/fsresizer/CMakeLists.txt @@ -0,0 +1,44 @@ +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 ) + find_package( Qt5 COMPONENTS Test REQUIRED ) + include( ECMAddTests ) + + 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..0589e1866 --- /dev/null +++ b/src/modules/fsresizer/ResizeFSJob.cpp @@ -0,0 +1,339 @@ +/* === 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/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 ) +{ +} + + +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 can not 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 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.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 can not be resized." ).arg(m_fsname) + : tr( "The device %1 can not 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 can not be resized." ).arg(m_fsname) + : tr( "The device %1 can not 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."; + 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() ); +} + +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..063495e7d --- /dev/null +++ b/src/modules/fsresizer/ResizeFSJob.h @@ -0,0 +1,121 @@ +/* === 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; + + 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..06141fc7d --- /dev/null +++ b/src/modules/fsresizer/fsresizer.conf @@ -0,0 +1,37 @@ +# 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. +# +# Percentages apply to **total device size**. +atleast: 1000MiB 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 8555adfdf..49ec4ad75 100644 --- a/src/modules/keyboard/kbd-model-map +++ b/src/modules/keyboard/kbd-model-map @@ -1,6 +1,14 @@ # Copied from systemd-localed -# http://cgit.freedesktop.org/systemd/systemd/log/src/locale/kbd-model-map +# +# https://cgit.freedesktop.org/systemd/systemd/log/src/locale/kbd-model-map # (originally under LGPLv2.1+, used under the LGPL to GPL conversion clause) +# +# 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 @@ -10,6 +18,7 @@ trq tr pc105 - terminate:ctrl_alt_bksp uk gb pc105 - terminate:ctrl_alt_bksp is-latin1 is 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/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/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 b5a2ce529..3f0e5a72a 100644 --- a/src/modules/partition/gui/ChoicePage.cpp +++ b/src/modules/partition/gui/ChoicePage.cpp @@ -50,6 +50,9 @@ #include #include +#ifdef WITH_KPMCOREGT33 +#include +#endif #include #include @@ -1230,6 +1233,13 @@ ChoicePage::setupActions() bool atLeastOneCanBeResized = false; bool atLeastOneCanBeReplaced = false; bool atLeastOneIsMounted = false; // Suppress 'erase' if so + bool isInactiveRAID = false; + +#ifdef WITH_KPMCOREGT33 + if ( currentDevice->type() == Device::Type::SoftwareRAID_Device && + static_cast< SoftwareRAID* >(currentDevice)->status() == SoftwareRAID::Status::Inactive ) + isInactiveRAID = true; +#endif for ( auto it = PartitionIterator::begin( currentDevice ); it != PartitionIterator::end( currentDevice ); ++it ) @@ -1353,7 +1363,7 @@ ChoicePage::setupActions() else force_uncheck( m_grp, m_alongsideButton ); - if ( !atLeastOneIsMounted ) + if ( !atLeastOneIsMounted && !isInactiveRAID ) m_eraseButton->show(); // None mounted else force_uncheck( m_grp, m_eraseButton ); diff --git a/src/modules/partition/gui/CreatePartitionDialog.cpp b/src/modules/partition/gui/CreatePartitionDialog.cpp index 0e7602c08..7823d743d 100644 --- a/src/modules/partition/gui/CreatePartitionDialog.cpp +++ b/src/modules/partition/gui/CreatePartitionDialog.cpp @@ -72,7 +72,7 @@ CreatePartitionDialog::CreatePartitionDialog( Device* device, PartitionNode* par m_ui->encryptWidget->setText( tr( "En&crypt" ) ); m_ui->encryptWidget->hide(); - if (m_device->type() == Device::Type::Disk_Device) { + if (m_device->type() != Device::Type::LVM_Device) { m_ui->lvNameLabel->hide(); m_ui->lvNameLineEdit->hide(); } diff --git a/src/modules/partition/gui/PartitionPage.cpp b/src/modules/partition/gui/PartitionPage.cpp index 994adc3e8..9d972c8fd 100644 --- a/src/modules/partition/gui/PartitionPage.cpp +++ b/src/modules/partition/gui/PartitionPage.cpp @@ -4,6 +4,7 @@ * Copyright 2015-2016, Teo Mrnjavac * Copyright 2018, Adriaan de Groot * Copyright 2018, Andrius Štikonas + * Copyright 2018, Caio Jordão Carvalho * * Calamares is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -47,6 +48,9 @@ // KPMcore #include #include +#ifdef WITH_KPMCOREGT33 +#include +#endif #include #include @@ -146,6 +150,7 @@ PartitionPage::updateButtons() bool isInVG = m_core->isInVG( partition ); create = isFree; + // Keep it simple for now: do not support editing extended partitions as // it does not work with our current edit implementation which is // actually remove + add. This would not work with extended partitions @@ -160,8 +165,20 @@ PartitionPage::updateButtons() if ( m_ui->deviceComboBox->currentIndex() >= 0 ) { QModelIndex deviceIndex = m_core->deviceModel()->index( m_ui->deviceComboBox->currentIndex(), 0 ); - if ( m_core->deviceModel()->deviceForIndex( deviceIndex )->type() != Device::Type::LVM_Device ) + auto device = m_core->deviceModel()->deviceForIndex( deviceIndex ); + if ( device->type() != Device::Type::LVM_Device ) + { createTable = true; + +#ifdef WITH_KPMCOREGT33 + if ( device->type() == Device::Type::SoftwareRAID_Device && + static_cast< SoftwareRAID* >(device)->status() == SoftwareRAID::Status::Inactive ) + { + createTable = false; + create = false; + } +#endif + } else { currentDeviceIsVG = true; 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; }