diff --git a/CHANGES b/CHANGES
index 1bdb681f0..c91e99299 100644
--- a/CHANGES
+++ b/CHANGES
@@ -7,18 +7,27 @@ contributors are listed. Note that Calamares does not have a historical
changelog -- this log starts with version 3.2.0. The release notes on the
website will have to do for older versions.
-# 3.2.44 (unreleased) #
+# 3.2.44 (2021-09-24) #
This release contains contributions from (alphabetically by first name):
+ - Anke Boersma
+ - Shrinivas Vishnu Kumbhar (new contributor, welcome!)
- whorfin (new contributor, welcome!)
## Core ##
- - No core changes yet
+ - "Log spam" has been reduced a little in the partitioning module.
## Modules ##
+ - *initcpiocfg* has had a number of internal code-fixes, and now adds
+ the `consolefont` hook by default as well. (Thanks Shrinivas)
+ - Both *locale* and *keyboard* have received some tweaks for configurations
+ in India; unless the user selects otherwise, English is preferred.
- The *luksbootkeyfile* module was reported to be too quick to declare
a timeout when applying the keyfile. The timeout has been increased
to one minute. (Thanks whorfin)
+ - *networkcfg* tries harder to find the live-user login for re-working
+ networking settings. This fixes a regression on FerenOS, where the
+ installer was crashing because it could not find the live-user login.
# 3.2.43 (2021-09-17) #
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 807cdfabf..b391cfeb2 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -45,7 +45,7 @@ project( CALAMARES
LANGUAGES C CXX
)
-set( CALAMARES_VERSION_RC 1 ) # Set to 0 during release cycle, 1 during development
+set( CALAMARES_VERSION_RC 0 ) # Set to 0 during release cycle, 1 during development
### OPTIONS
#
diff --git a/lang/calamares_cs_CZ.ts b/lang/calamares_cs_CZ.ts
index 1c2ed1755..5714c4e31 100644
--- a/lang/calamares_cs_CZ.ts
+++ b/lang/calamares_cs_CZ.ts
@@ -134,7 +134,7 @@
- Strom widgetu
+ Strom ovládacích prvků
@@ -217,7 +217,7 @@
- Pracovní složku %1 pro Python skript %2 se nedaří otevřít pro čtení.
+ Pracovní složka %1 pro Python skript %2 není přístupná pro čtení.
@@ -227,7 +227,7 @@
- Hlavní soubor s python skriptem %1 pro úlohu %2 se nedaří otevřít pro čtení..
+ Hlavní soubor Python skriptu %1 pro úlohu %2 není přístupný pro čtení.
@@ -504,7 +504,7 @@ Instalační program bude ukončen a všechny změny ztraceny.
- %1 instalátor
+ Instalátor %1
@@ -660,7 +660,7 @@ Instalační program bude ukončen a všechny změny ztraceny.
- Toto úložné zařízení je součástí <strong>Neaktivního RAID</strong> zařízení.
+ Toto úložné zařízení je součástí <strong>neaktivního RAID</strong> zařízení.
@@ -758,7 +758,7 @@ Instalační program bude ukončen a všechny změny ztraceny.
- Nastavit rozložení klávesnice na %1/%2.
+ Nastavit rozvržení klávesnice na %1/%2.
@@ -808,7 +808,7 @@ Instalační program bude ukončen a všechny změny ztraceny.
- Počítač nesplňuje minimální požadavky pro instalaci %1.<br/>Instalace nemůže pokračovat <a href="#details">Podrobnosti…</a>
+ Počítač nesplňuje minimální požadavky pro instalaci %1.<br/>Nastavování nemůže pokračovat <a href="#details">Podrobnosti…</a>
@@ -953,7 +953,7 @@ Instalační program bude ukončen a všechny změny ztraceny.
- Možnost instalace: <strong>%1</strong>
+ Volba instalace: <strong>%1</strong>
@@ -1182,7 +1182,7 @@ Instalační program bude ukončen a všechny změny ztraceny.
- Zachování domovské složky
+ Zachovává se domovská složka
@@ -1198,7 +1198,7 @@ Instalační program bude ukončen a všechny změny ztraceny.
- Nastavení oprávnění souboru
+ Nastavují se přístupová práva k souboru
@@ -1755,7 +1755,7 @@ Instalační program bude ukončen a všechny změny ztraceny.
- Místní a jazykové nastavení systému
+ Místní a jazyková nastavení systému
@@ -1986,7 +1986,7 @@ Instalační program bude ukončen a všechny změny ztraceny.
- Časová zóna: %1
+ Časové pásmo: %1
@@ -2152,12 +2152,12 @@ Instalační program bude ukončen a všechny změny ztraceny.
- Vyberte preferovanou zónu ve vašem regionu.
+ Vyberte upřednostňované pásmo ve svém regionu.
- Zóny
+ Pásma
@@ -2283,7 +2283,7 @@ Instalační program bude ukončen a všechny změny ztraceny.
Heslo obsahuje méně než %1 čísliciHeslo obsahuje méně než %1 číslice
- Heslo obsahuje méně než %1 číslice
+ Heslo obsahuje méně než %1 číslicHeslo obsahuje méně než %1 číslice
@@ -2463,7 +2463,7 @@ Instalační program bude ukončen a všechny změny ztraceny.
- Form
+ Formulář
@@ -2724,7 +2724,7 @@ Instalační program bude ukončen a všechny změny ztraceny.
- Form
+ Formulář
@@ -3609,7 +3609,7 @@ Výstup:
- Tyto skupiny chybí v cílovém systému chybí: %1
+ Tyto skupiny v cílovém systému chybí: %1
@@ -3703,7 +3703,7 @@ Výstup:
- Zpětná vazba uživatele KDE
+ Zpětná vazba od uživatele pro KDE
@@ -3719,12 +3719,12 @@ Výstup:
- Nepodařilo se správně nastavit zpětnou vazbu KDE uživatele, chyba ve skriptu %1.
+ Nepodařilo se správně nastavit zpětnou vazbu od uživatele pro KDE, chyba ve skriptu %1.
- Nepodařilo se správně nastavit zpětnou vazbu KDE uživatele, chyba Calamares %1.
+ Nepodařilo se správně nastavit zpětnou vazbu od uživatel pro KDE, chyba Calamares %1.
@@ -3732,28 +3732,28 @@ Výstup:
- Zpětná vazba stroje
+ Zpětná vazba ze stroje
- Nastavování zpětné vazby stroje
+ Nastavování zpětné vazby ze stroje
- Chyba v nastavení zpětné vazby stroje.
+ Chyba v nastavení zpětné vazby ze stroje.
- Nepodařilo se správně nastavit zpětnou vazbu stroje, chyba skriptu %1.
+ Nepodařilo se správně nastavit zpětnou vazbu ze stroje, chyba skriptu %1.
- Nepodařilo se správně nastavit zpětnou vazbu stroje, chyba Calamares %1.
+ Nepodařilo se správně nastavit zpětnou vazbu ze stroje, chyba Calamares %1.
@@ -3786,7 +3786,7 @@ Výstup:
- Výběrem tohoto pošlete informace o své instalaci a hardware. Tyto údaje budou poslány <b>pouze jednorázově</b> po dokončení instalace.
+ Výběrem tohoto pošlete informace o své instalaci a hardware. Tyto údaje budou odeslány <b>pouze jednorázově</b> po dokončení instalace.
@@ -3975,7 +3975,7 @@ Výstup:
- <h1>Vítejte v Calamares, instalačním programu (nejen) pro %1.</h1>
+ <h1>Vítejte v Calamares, instalačním programu (nejen) pro %1.</h1>
@@ -4121,7 +4121,7 @@ Výstup:
-
+ Pokud chcete aktivovat náhled klávesnice, vyberte rozvržení.
@@ -4131,7 +4131,7 @@ Výstup:
- Rovzržení
+ Rozvržení
@@ -4179,7 +4179,7 @@ Výstup:
- Pokud nechcete nainstalovat žádnou sadu kancelářských aplikací, stačí jen zvolit Žádná sada kancelářských aplikací. V případě potřeby je možné kdykoli nějakou přidat na už nainstalovaný systém.
+ Pokud nechcete nainstalovat žádnou sadu kancelářských aplikací, stačí jen zvolit Žádná sada kancelářských aplikací. V případě potřeby je možné kdykoli nějakou přidat do už nainstalovaného systému.
@@ -4310,7 +4310,7 @@ Výstup:
- Tento název se použije, pokud počítač zviditelníte ostatním v síti.
+ Pod tímto názvem se bude počítač případně zobrazovat ostatním počítačům v síti.
@@ -4335,7 +4335,7 @@ Výstup:
- Zadejte dvakrát stejné heslo, aby bylo možné zkontrolovat chyby při psaní. Dobré heslo by mělo obsahovat směs písmen, čísel a interpunkce a mělo by mít alespoň osm znaků. Zvažte také jeho pravidelnou změnu.
+ Zadání hesla zopakujte i do kontrolní kolonky, abyste měli jistotu, že jste napsali, co zamýšleli (že nedošlo k překlepu). Dobré heslo se bude skládat z písmen, číslic a interpunkce a mělo by být alespoň osm znaků dlouhé. Heslo byste také měli pravidelně měnit (prevence škod z jeho případného prozrazení).
@@ -4350,7 +4350,7 @@ Výstup:
- Přihlaste se automaticky bez zadávání hesla
+ Přihlašovat se automaticky bez zadávání hesla
@@ -4360,7 +4360,7 @@ Výstup:
- Použijte uživatelské heslo zároveň jako heslo root
+ Použijte heslo uživatele i pro účet správce (root)
@@ -4380,12 +4380,12 @@ Výstup:
- Opakujte root heslo
+ Zopakujte zadání hesla pro správce systému (root)
- Zadejte dvakrát stejné heslo, aby bylo možné zkontrolovat chyby při psaní.
+ Zadání hesla zopakujte i do kontrolní kolonky, abyste měli jistotu, že jste napsali, co zamýšleli (že nedošlo k překlepu).
diff --git a/lang/python/az/LC_MESSAGES/python.po b/lang/python/az/LC_MESSAGES/python.po
index f4c40e5ab..8ac8172d8 100644
--- a/lang/python/az/LC_MESSAGES/python.po
+++ b/lang/python/az/LC_MESSAGES/python.po
@@ -4,7 +4,7 @@
# FIRST AUTHOR , YEAR.
#
# Translators:
-# xxmn77 , 2021
+# Xəyyam Qocayev , 2021
#
#, fuzzy
msgid ""
@@ -13,7 +13,7 @@ msgstr ""
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2021-09-08 13:31+0200\n"
"PO-Revision-Date: 2017-08-09 10:34+0000\n"
-"Last-Translator: xxmn77 , 2021\n"
+"Last-Translator: Xəyyam Qocayev , 2021\n"
"Language-Team: Azerbaijani (https://www.transifex.com/calamares/teams/20061/az/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
diff --git a/lang/python/az_AZ/LC_MESSAGES/python.po b/lang/python/az_AZ/LC_MESSAGES/python.po
index 2d57f0d4b..0df66e711 100644
--- a/lang/python/az_AZ/LC_MESSAGES/python.po
+++ b/lang/python/az_AZ/LC_MESSAGES/python.po
@@ -4,7 +4,7 @@
# FIRST AUTHOR , YEAR.
#
# Translators:
-# xxmn77 , 2021
+# Xəyyam Qocayev , 2021
#
#, fuzzy
msgid ""
@@ -13,7 +13,7 @@ msgstr ""
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2021-09-08 13:31+0200\n"
"PO-Revision-Date: 2017-08-09 10:34+0000\n"
-"Last-Translator: xxmn77 , 2021\n"
+"Last-Translator: Xəyyam Qocayev , 2021\n"
"Language-Team: Azerbaijani (Azerbaijan) (https://www.transifex.com/calamares/teams/20061/az_AZ/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
diff --git a/lang/python/cs_CZ/LC_MESSAGES/python.po b/lang/python/cs_CZ/LC_MESSAGES/python.po
index 6305ba7fb..993ed0b3f 100644
--- a/lang/python/cs_CZ/LC_MESSAGES/python.po
+++ b/lang/python/cs_CZ/LC_MESSAGES/python.po
@@ -206,8 +206,8 @@ msgid ""
"The displaymanagers list is empty or undefined in both globalstorage and "
"displaymanager.conf."
msgstr ""
-"Seznam správců displejů je prázdný nebo není definován v jak "
-"bothglobalstorage, tak v displaymanager.conf."
+"Seznam správců displejů je prázdný nebo není definován v jak globalstorage, "
+"tak v displaymanager.conf."
#: src/modules/displaymanager/main.py:989
msgid "Display manager configuration was incomplete"
@@ -343,7 +343,7 @@ msgid ""
"The package manager could not make changes to the installed system. The "
"command
{!s}
returned error code {!s}."
msgstr ""
-"Nástroji pro správu balíčků se nepodařilo udělat změny v nainstalovaném "
+"Nástroji pro správu balíčků se nepodařilo udělat změny v instalovaném "
"systému. Příkaz
{!s}
vrátil chybový kód {!s}."
#: src/modules/bootloader/main.py:43
diff --git a/src/libcalamares/JobQueue.cpp b/src/libcalamares/JobQueue.cpp
index 00b30f318..039a28e26 100644
--- a/src/libcalamares/JobQueue.cpp
+++ b/src/libcalamares/JobQueue.cpp
@@ -112,17 +112,19 @@ public:
QString message; ///< Filled in with errors
QString details;
+ Logger::Once o;
m_jobIndex = 0;
for ( const auto& jobitem : *m_runningJobs )
{
if ( failureEncountered && !jobitem.job->isEmergency() )
{
- cDebug() << "Skipping non-emergency job" << jobitem.job->prettyName();
+ cDebug() << o << "Skipping non-emergency job" << jobitem.job->prettyName();
}
else
{
- cDebug() << "Starting" << ( failureEncountered ? "EMERGENCY JOB" : "job" ) << jobitem.job->prettyName()
+ cDebug() << o << "Starting" << ( failureEncountered ? "EMERGENCY JOB" : "job" ) << jobitem.job->prettyName()
<< '(' << ( m_jobIndex + 1 ) << '/' << m_runningJobs->count() << ')';
+ o.refresh(); // So next time it shows the function header again
emitProgress( 0.0 ); // 0% for *this job*
connect( jobitem.job.data(), &Job::progress, this, &JobThread::emitProgress );
auto result = jobitem.job->exec();
diff --git a/src/libcalamares/PythonJobApi.cpp b/src/libcalamares/PythonJobApi.cpp
index d61cfc223..480a115ae 100644
--- a/src/libcalamares/PythonJobApi.cpp
+++ b/src/libcalamares/PythonJobApi.cpp
@@ -16,6 +16,7 @@
#include "partition/Mount.h"
#include "utils/CalamaresUtilsSystem.h"
#include "utils/Logger.h"
+#include "utils/RAII.h"
#include "utils/String.h"
#include
@@ -147,7 +148,7 @@ debug( const std::string& s )
void
warning( const std::string& s )
{
- Logger::CDebug( Logger::LOGWARNING ) << output_prefix << QString::fromStdString( s );
+ Logger::CDebug( Logger::LOGWARNING ) << output_prefix << QString::fromStdString( s );
}
PythonJobInterface::PythonJobInterface( Calamares::PythonJob* parent )
@@ -241,6 +242,10 @@ _add_localedirs( QStringList& pathList, const QString& candidate )
bp::object
gettext_path()
{
+ // Going to log informatively just once
+ static bool first_time = true;
+ cScopedAssignment( &first_time, false );
+
// TODO: distinguish between -d runs and normal runs
// TODO: can we detect DESTDIR-installs?
QStringList candidatePaths
@@ -257,21 +262,26 @@ gettext_path()
}
_add_localedirs( candidatePaths, QDir().canonicalPath() ); // .
- cDebug() << "Determining gettext path from" << candidatePaths;
+ if ( first_time )
+ {
+ cDebug() << "Determining gettext path from" << candidatePaths;
+ }
QStringList candidateLanguages = _gettext_languages();
-
for ( const auto& lang : candidateLanguages )
+ {
for ( auto localedir : candidatePaths )
{
QDir ldir( localedir );
if ( ldir.cd( lang ) )
{
- cDebug() << Logger::SubEntry << "Found" << lang << "in" << ldir.canonicalPath();
+ Logger::CDebug( Logger::LOGDEBUG )
+ << output_prefix << "Found gettext" << lang << "in" << ldir.canonicalPath();
return bp::object( localedir.toStdString() );
}
}
- cDebug() << Logger::SubEntry << "No translation found for languages" << candidateLanguages;
+ }
+ cWarning() << "No translation found for languages" << candidateLanguages;
return bp::object(); // None
}
diff --git a/src/libcalamares/modulesystem/Module.cpp b/src/libcalamares/modulesystem/Module.cpp
index ff0b20f78..8fbb05300 100644
--- a/src/libcalamares/modulesystem/Module.cpp
+++ b/src/libcalamares/modulesystem/Module.cpp
@@ -101,7 +101,7 @@ Module::loadConfigurationFile( const QString& configFileName ) //throws YAML::E
YAML::Node doc = YAML::Load( ba.constData() );
if ( doc.IsNull() )
{
- cDebug() << "Found empty module configuration" << path;
+ cWarning() << "Found empty module configuration" << path;
// Special case: empty config files are valid,
// but aren't a map.
return;
@@ -112,14 +112,13 @@ Module::loadConfigurationFile( const QString& configFileName ) //throws YAML::E
return;
}
- cDebug() << "Loaded module configuration" << path;
m_configurationMap = CalamaresUtils::yamlMapToVariant( doc );
m_emergency = m_maybe_emergency && m_configurationMap.contains( EMERGENCY )
&& m_configurationMap[ EMERGENCY ].toBool();
return;
}
}
- cDebug() << "No config file for" << name() << "found anywhere at" << Logger::DebugList( configCandidates );
+ cWarning() << "No config file for" << name() << "found anywhere at" << Logger::DebugList( configCandidates );
}
diff --git a/src/libcalamares/partition/KPMManager.cpp b/src/libcalamares/partition/KPMManager.cpp
index 5f6b87589..ff7701703 100644
--- a/src/libcalamares/partition/KPMManager.cpp
+++ b/src/libcalamares/partition/KPMManager.cpp
@@ -100,12 +100,10 @@ getInternal()
KPMManager::KPMManager()
: m_d( getInternal() )
{
- cDebug() << "KPMManager" << s_backend.use_count() << "created.";
}
KPMManager::~KPMManager()
{
- cDebug() << "KPMManager" << s_backend.use_count() << "being destroyed.";
}
KPMManager::operator bool() const
diff --git a/src/libcalamares/utils/CalamaresUtilsSystem.cpp b/src/libcalamares/utils/CalamaresUtilsSystem.cpp
index df578a862..d2c0a6cf1 100644
--- a/src/libcalamares/utils/CalamaresUtilsSystem.cpp
+++ b/src/libcalamares/utils/CalamaresUtilsSystem.cpp
@@ -169,7 +169,7 @@ System::runCommand( System::RunLocation location,
}
}
- cDebug() << "Running" << program << RedactedList( arguments );
+ cDebug() << Logger::SubEntry << "Running" << program << RedactedList( arguments );
process.start();
if ( !process.waitForStarted() )
{
@@ -208,10 +208,6 @@ System::runCommand( System::RunLocation location,
{
cDebug() << Logger::SubEntry << "Finished. Exit code:" << r << "output:\n" << Logger::NoQuote << output;
}
- else
- {
- cDebug() << Logger::SubEntry << "Finished. Exit code:" << r;
- }
}
else // if ( r != 0 )
{
diff --git a/src/libcalamares/utils/Logger.h b/src/libcalamares/utils/Logger.h
index 871cc6fb3..1fd534d04 100644
--- a/src/libcalamares/utils/Logger.h
+++ b/src/libcalamares/utils/Logger.h
@@ -310,6 +310,14 @@ public:
}
friend CDebug& operator<<( CDebug&&, const Once& );
+ /** @brief Restore the object to "fresh" state
+ *
+ * It may be necessary to allow the Once object to stream the
+ * function header again -- for instance, after logging an error,
+ * any following debug log might want to re-introduce the header.
+ */
+ void refresh() { m = true; }
+
private:
mutable bool m = false;
};
diff --git a/src/libcalamares/utils/RAII.h b/src/libcalamares/utils/RAII.h
index 00e276ec6..957e4fe42 100644
--- a/src/libcalamares/utils/RAII.h
+++ b/src/libcalamares/utils/RAII.h
@@ -42,30 +42,17 @@ struct cqDeleter
}
};
-/// @brief Sets a bool to @p value and resets to !value on destruction
-template < bool value >
-struct cBoolSetter
-{
- bool& m_b;
-
- cBoolSetter( bool& b )
- : m_b( b )
- {
- m_b = value;
- }
- ~cBoolSetter() { m_b = !value; }
-};
-
/// @brief Blocks signals on a QObject until destruction
using cSignalBlocker = QSignalBlocker;
/** @brief Writes a value on destruction to a pointed-to location.
*
* If the pointer is non-null, write the last-given-value if there
- * is one to the pointed-to object.
+ * is one to the pointed-to object. This is called the "then-value".
+ *
*/
template < typename T >
-struct cPointerSetter
+struct cScopedAssignment
{
std::optional< T > m_value;
T* m_pointer;
@@ -76,22 +63,36 @@ struct cPointerSetter
* will do nothing on destruction, leaving the pointed-to
* value unchanged.
*/
- cPointerSetter( T* p )
+ cScopedAssignment( T* p )
: m_pointer( p )
{
}
- /** @brief Create a setter with a value already set
+ /** @brief Create a setter with a then-value already set
*
* This ensures that on destruction, the value @p v will be written;
* it is equivalent to assigning @p v immediately. The pointed-to
* value is **not** changed (until destruction).
*/
- cPointerSetter( T* p, T v )
- : m_value( v )
+ cScopedAssignment( T* p, T then )
+ : m_value( then )
, m_pointer( p )
{
}
- ~cPointerSetter()
+ /** @brief Create a setter with a then-value and assign a new value now
+ *
+ * As above, but also assign @p now to the thing pointed-to.
+ */
+ cScopedAssignment( T* p, T now, T then )
+ : m_value( then )
+ , m_pointer( p )
+ {
+ if ( p )
+ {
+ *p = now;
+ }
+ }
+
+ ~cScopedAssignment()
{
if ( m_pointer && m_value.has_value() )
{
@@ -99,13 +100,13 @@ struct cPointerSetter
}
}
- const T& operator=( const T& v )
+ const T& operator=( const T& then )
{
- m_value = v;
- return v;
+ m_value = then;
+ return then;
}
};
template < typename T >
-cPointerSetter( T p )->cPointerSetter< decltype( *p ) >;
+cScopedAssignment( T p )->cScopedAssignment< decltype( *p ) >;
#endif
diff --git a/src/libcalamares/utils/Tests.cpp b/src/libcalamares/utils/Tests.cpp
index a689505e9..c652571b4 100644
--- a/src/libcalamares/utils/Tests.cpp
+++ b/src/libcalamares/utils/Tests.cpp
@@ -55,7 +55,6 @@ private Q_SLOTS:
void testOddSizedPrintable();
/** @section Tests the RAII bits. */
- void testBoolSetter();
void testPointerSetter();
/** @section Tests the Traits bits. */
@@ -340,28 +339,6 @@ LibCalamaresTests::testOddSizedPrintable()
}
}
-void
-LibCalamaresTests::testBoolSetter()
-{
- bool b = false;
-
- QVERIFY( !b );
- {
- QVERIFY( !b );
- cBoolSetter< true > x( b );
- QVERIFY( b );
- }
- QVERIFY( !b );
-
- QVERIFY( !b );
- {
- QVERIFY( !b );
- cBoolSetter< false > x( b );
- QVERIFY( !b ); // Still!
- }
- QVERIFY( b );
-}
-
void
LibCalamaresTests::testPointerSetter()
{
@@ -369,35 +346,35 @@ LibCalamaresTests::testPointerSetter()
QCOMPARE( special, 17 );
{
- cPointerSetter p( &special );
+ cScopedAssignment p( &special );
}
QCOMPARE( special, 17 );
{
- cPointerSetter p( &special );
+ cScopedAssignment p( &special );
p = 18;
}
QCOMPARE( special, 18 );
{
- cPointerSetter p( &special );
+ cScopedAssignment p( &special );
p = 20;
p = 3;
}
QCOMPARE( special, 3 );
{
- cPointerSetter p( nullptr );
+ cScopedAssignment< int > p( nullptr );
}
QCOMPARE( special, 3 );
{
// "don't do this" .. order of destructors is important
- cPointerSetter p( &special );
- cPointerSetter q( &special );
+ cScopedAssignment p( &special );
+ cScopedAssignment q( &special );
p = 17;
}
QCOMPARE( special, 17 );
{
// "don't do this" .. order of destructors is important
- cPointerSetter p( &special );
- cPointerSetter q( &special );
+ cScopedAssignment p( &special );
+ cScopedAssignment q( &special );
p = 34;
q = 2;
// q destroyed first, then p
@@ -490,8 +467,7 @@ LibCalamaresTests::testVariantStringListCode()
QStringList { "astring" } ); // A single string **can** be considered a stringlist!
m.insert( key, QString( "more strings" ) );
QCOMPARE( getStringList( m, key ).count(), 1 );
- QCOMPARE( getStringList( m, key ),
- QStringList { "more strings" } );
+ QCOMPARE( getStringList( m, key ), QStringList { "more strings" } );
m.insert( key, QString() );
QCOMPARE( getStringList( m, key ).count(), 1 );
QCOMPARE( getStringList( m, key ), QStringList { QString() } );
diff --git a/src/modules/fstab/fstab.conf b/src/modules/fstab/fstab.conf
index a14165e15..33fb2c937 100644
--- a/src/modules/fstab/fstab.conf
+++ b/src/modules/fstab/fstab.conf
@@ -13,7 +13,7 @@
# options from this mapping.
mountOptions:
default: defaults,noatime
- btrfs: defaults,noatime,space_cache
+ btrfs: defaults,noatime,space_cache,autodefrag,compress=zstd
# Mount options to use for the EFI System Partition. If not defined, the
# *mountOptions* for *vfat* are used, or if that is not set either,
@@ -38,10 +38,10 @@ efiMountOptions: umask=0077
# swap: discard
# btrfs: discard,compress=lzo
#
-# The standard configuration applies only lzo compression to btrfs
+# The standard configuration applies asynchronous discard support and ssd optimizations to btrfs
# and does nothing for other filesystems.
ssdExtraMountOptions:
- btrfs: ssd,compress=zstd,commit=120
+ btrfs: discard=async,ssd,compress=zstd,commit=120
# Additional options added to each line in /etc/crypttab
crypttabOptions: luks
diff --git a/src/modules/initcpiocfg/main.py b/src/modules/initcpiocfg/main.py
index 3aa6287a1..b89d0b0b9 100644
--- a/src/modules/initcpiocfg/main.py
+++ b/src/modules/initcpiocfg/main.py
@@ -28,35 +28,84 @@ def pretty_name():
return _("Configuring mkinitcpio.")
-def cpuinfo():
+def detect_plymouth():
"""
- Return the information in /proc/cpuinfo as a dictionary in the following
- format:
+ Checks existence (runnability) of plymouth in the target system.
- cpu_info['proc0']={...}
- cpu_info['proc1']={...}
+ @return True if plymouth exists in the target, False otherwise
"""
- cpu_info = OrderedDict()
- procinfo = OrderedDict()
+ # Used to only check existence of path /usr/bin/plymouth in target
+ return target_env_call(["sh", "-c", "which plymouth"]) == 0
- nprocs = 0
- with open('/proc/cpuinfo') as cpuinfo_file:
- for line in cpuinfo_file:
- if not line.strip():
- # end of one processor
- cpu_info["proc{!s}".format(nprocs)] = procinfo
- nprocs += 1
- # Reset
- procinfo = OrderedDict()
- else:
- if len(line.split(':')) == 2:
- splitted_line = line.split(':')[1].strip()
- procinfo[line.split(':')[0].strip()] = splitted_line
+class cpuinfo(object):
+ """
+ Object describing the current CPU's characteristics. It may be
+ be considered a named tuple, there's no behavior here.
+
+ Fields in the object:
+ - is_intel (if it's definitely an Intel CPU)
+ - is_amd (if it's definitely an AMD CPU)
+ - number_of_cores
+ It is possible for both is_* fields to be False.
+ """
+ def __init__(self):
+ self.is_intel = False
+ self.is_amd = False
+ self.number_of_cores = 0
+
+ cpu = self._cpuinfo()
+ self.is_intel = cpu['proc0']['vendor_id'].lower() == "genuineintel"
+ self.is_amd = cpu['proc0']['vendor_id'].lower() == "authenticamd"
+ self.number_of_cores = len(cpu)
+
+ @staticmethod
+ def _cpuinfo():
+ """
+ Return the information in /proc/cpuinfo as a dictionary in the following
+ format:
+
+ cpu_info['proc0']={...}
+ cpu_info['proc1']={...}
+ """
+ cpu_info = OrderedDict()
+ procinfo = OrderedDict()
+
+ nprocs = 0
+
+ with open('/proc/cpuinfo') as cpuinfo_file:
+ for line in cpuinfo_file:
+ if not line.strip():
+ # end of one processor
+ cpu_info["proc{!s}".format(nprocs)] = procinfo
+ nprocs += 1
+ # Reset
+ procinfo = OrderedDict()
else:
- procinfo[line.split(':')[0].strip()] = ''
+ if len(line.split(':')) == 2:
+ splitted_line = line.split(':')[1].strip()
+ procinfo[line.split(':')[0].strip()] = splitted_line
+ else:
+ procinfo[line.split(':')[0].strip()] = ''
- return cpu_info
+ return cpu_info
+
+
+def get_host_initcpio():
+ """
+ Reads the host system mkinitcpio.conf and returns all
+ the lines from that file, or an empty list if it does
+ not exist.
+ """
+ hostfile = "/etc/mkinitcpio.conf"
+ try:
+ with open(hostfile, "r") as mkinitcpio_file:
+ mklins = [x.strip() for x in mkinitcpio_file.readlines()]
+ except FileNotFoundError:
+ libcalamares.utils.debug("Could not open host file '%s'" % hostfile)
+ mklins = []
+
+ return mklins
def write_mkinitcpio_lines(hooks, modules, files, root_mount_point):
@@ -68,56 +117,40 @@ def write_mkinitcpio_lines(hooks, modules, files, root_mount_point):
:param files:
:param root_mount_point:
"""
- hostfile = "/etc/mkinitcpio.conf"
- try:
- with open(hostfile, "r") as mkinitcpio_file:
- mklins = [x.strip() for x in mkinitcpio_file.readlines()]
- except FileNotFoundError:
- libcalamares.utils.debug("Could not open host file '%s'" % hostfile)
- mklins = []
+ mklins = get_host_initcpio()
- for i in range(len(mklins)):
- if mklins[i].startswith("HOOKS"):
- joined_hooks = ' '.join(hooks)
- mklins[i] = "HOOKS=\"{!s}\"".format(joined_hooks)
- elif mklins[i].startswith("MODULES"):
- joined_modules = ' '.join(modules)
- mklins[i] = "MODULES=\"{!s}\"".format(joined_modules)
- elif mklins[i].startswith("FILES"):
- joined_files = ' '.join(files)
- mklins[i] = "FILES=\"{!s}\"".format(joined_files)
-
- path = os.path.join(root_mount_point, "etc/mkinitcpio.conf")
-
- with open(path, "w") as mkinitcpio_file:
- mkinitcpio_file.write("\n".join(mklins) + "\n")
+ target_path = os.path.join(root_mount_point, "etc/mkinitcpio.conf")
+ with open(target_path, "w") as mkinitcpio_file:
+ for line in mklins:
+ # Replace HOOKS, MODULES and FILES lines with what we
+ # have found via find_initcpio_features()
+ if line.startswith("HOOKS"):
+ line = "HOOKS=\"{!s}\"".format(' '.join(hooks))
+ elif line.startswith("MODULES"):
+ line = "MODULES=\"{!s}\"".format(' '.join(modules))
+ elif line.startswith("FILES"):
+ line = "FILES=\"{!s}\"".format(' '.join(files))
+ mkinitcpio_file.write(line + "\n")
-def detect_plymouth():
+def find_initcpio_features(partitions, root_mount_point):
"""
- Checks existence (runnability) of plymouth in the target system.
+ Returns a tuple (hooks, modules, files) needed to support
+ the given @p partitions (filesystems types, encryption, etc)
+ in the target.
- @return True if plymouth exists in the target, False otherwise
+ :param partitions: (from GS)
+ :param root_mount_point: (from GS)
+
+ :return 3-tuple of lists
"""
- # Used to only check existence of path /usr/bin/plymouth in target
- return target_env_call(["sh", "-c", "which plymouth"]) == 0
-
-
-def modify_mkinitcpio_conf(partitions, root_mount_point):
- """
- Modifies mkinitcpio.conf
-
- :param partitions:
- :param root_mount_point:
- """
- cpu = cpuinfo()
- swap_uuid = ""
- btrfs = ""
- lvm2 = ""
- hooks = ["base", "udev", "autodetect", "modconf", "block", "keyboard",
- "keymap"]
+ hooks = ["base", "udev", "autodetect", "modconf", "block", "keyboard", "keymap", "consolefont"]
modules = []
files = []
+
+ swap_uuid = ""
+ uses_btrfs = False
+ uses_lvm2 = False
encrypt_hook = False
openswap_hook = False
unencrypted_separate_boot = False
@@ -144,10 +177,10 @@ def modify_mkinitcpio_conf(partitions, root_mount_point):
openswap_hook = True
if partition["fs"] == "btrfs":
- btrfs = "yes"
+ uses_btrfs = True
if "lvm2" in partition["fs"]:
- lvm2 = "yes"
+ uses_lvm2 = True
if partition["mountPoint"] == "/" and "luksMapperName" in partition:
encrypt_hook = True
@@ -169,7 +202,7 @@ def modify_mkinitcpio_conf(partitions, root_mount_point):
):
files.append("/crypto_keyfile.bin")
- if lvm2:
+ if uses_lvm2:
hooks.append("lvm2")
if swap_uuid != "":
@@ -179,15 +212,12 @@ def modify_mkinitcpio_conf(partitions, root_mount_point):
else:
hooks.extend(["filesystems"])
- if btrfs == "yes" and cpu['proc0']['vendor_id'].lower() != "genuineintel":
- modules.append("crc32c")
- elif (btrfs == "yes"
- and cpu['proc0']['vendor_id'].lower() == "genuineintel"):
- modules.append("crc32c-intel")
+ if uses_btrfs:
+ modules.append("crc32c-intel" if cpuinfo().is_intel else "crc32c")
else:
hooks.append("fsck")
- write_mkinitcpio_lines(hooks, modules, files, root_mount_point)
+ return (hooks, modules, files)
def run():
@@ -208,6 +238,7 @@ def run():
return (_("Configuration Error"),
_("No root mount point is given for
{!s}
to use." ).format("initcpiocfg"))
- modify_mkinitcpio_conf(partitions, root_mount_point)
+ hooks, modules, files = find_initcpio_features(partitions, root_mount_point)
+ write_mkinitcpio_lines(hooks, modules, files, root_mount_point)
return None
diff --git a/src/modules/initcpiocfg/module.desc b/src/modules/initcpiocfg/module.desc
index a4476121b..a64fdf173 100644
--- a/src/modules/initcpiocfg/module.desc
+++ b/src/modules/initcpiocfg/module.desc
@@ -1,7 +1,13 @@
# SPDX-FileCopyrightText: no
# SPDX-License-Identifier: CC0-1.0
+#
+# Writes a mkinitcpio.conf into the target system. It copies
+# the host system's /etc/mkinitcpio.conf, and replaces any
+# HOOKS, MODULES, and FILES lines with calculated values
+# based on what the installation (seems to) need.
---
type: "job"
name: "initcpiocfg"
interface: "python"
script: "main.py"
+noconfig: true
diff --git a/src/modules/keyboard/Config.cpp b/src/modules/keyboard/Config.cpp
index 7140bd790..720588810 100644
--- a/src/modules/keyboard/Config.cpp
+++ b/src/modules/keyboard/Config.cpp
@@ -275,7 +275,7 @@ Config::detectCurrentKeyboardLayout()
{
return;
}
- cPointerSetter returnToIntial( &m_state, State::Initial );
+ cScopedAssignment returnToIntial( &m_state, State::Initial );
m_state = State::Guessing;
//### Detect current keyboard layout and variant
@@ -427,7 +427,7 @@ Config::guessLocaleKeyboardLayout()
{
return;
}
- cPointerSetter returnToIntial( &m_state, State::Initial );
+ cScopedAssignment returnToIntial( &m_state, State::Initial );
m_state = State::Guessing;
/* Guessing a keyboard layout based on the locale means
@@ -472,7 +472,7 @@ Config::guessLocaleKeyboardLayout()
{ "el_GR", "gr" }, /* Greek in Greece */
{ "ig_NG", "igbo_NG" }, /* Igbo in Nigeria */
{ "ha_NG", "hausa_NG" }, /* Hausa */
- { "en_IN", "eng_in" }, /* India, English with Rupee */
+ { "en_IN", "us" }, /* India, US English keyboards are common in India */
} );
// Try to preselect a layout, depending on language and locale
diff --git a/src/modules/locale/LocaleConfiguration.cpp b/src/modules/locale/LocaleConfiguration.cpp
index c208dc02d..b7b895290 100644
--- a/src/modules/locale/LocaleConfiguration.cpp
+++ b/src/modules/locale/LocaleConfiguration.cpp
@@ -201,6 +201,10 @@ LocaleConfiguration::fromLanguageAndLocation( const QString& languageLocale,
// but nearly all its native speakers also speak English,
// and migrants are likely to use English.
{ "IE", "en" },
+ // India has many languages even though Hindi is known as
+ // national language but English is used in all computer
+ // and mobile devices.
+ { "IN", "en" },
{ "IT", "it" },
{ "MA", "ar" },
{ "MK", "mk" },
diff --git a/src/modules/locale/LocalePage.cpp b/src/modules/locale/LocalePage.cpp
index f63aed10d..236f63ec3 100644
--- a/src/modules/locale/LocalePage.cpp
+++ b/src/modules/locale/LocalePage.cpp
@@ -174,7 +174,7 @@ LocalePage::locationChanged( const CalamaresUtils::Locale::TimeZoneData* locatio
{
return;
}
- cBoolSetter< true > b( m_blockTzWidgetSet );
+ cScopedAssignment b( &m_blockTzWidgetSet, true, false );
// Set region index
int index = m_regionCombo->findData( location->region() );
diff --git a/src/modules/networkcfg/main.py b/src/modules/networkcfg/main.py
index 35bf67d63..4dc6cbbf7 100644
--- a/src/modules/networkcfg/main.py
+++ b/src/modules/networkcfg/main.py
@@ -29,23 +29,83 @@ def pretty_name():
return _("Saving network configuration.")
+def get_live_user():
+ """
+ Gets the "live user" login. This might be "live", or "nitrux",
+ or something similar: it is the login name used *right now*,
+ and network configurations saved for that user, should be applied
+ also for the installed user (which probably has a different name).
+ """
+ # getlogin() is a thin-wrapper, and depends on getlogin(3),
+ # which reads utmp -- and utmp isn't always set up right.
+ try:
+ return os.getlogin()
+ except OSError:
+ pass
+ # getpass will return the **current** user, which is generally root.
+ # That isn't very useful, because the network settings have been
+ # made outside of Calamares-running-as-root, as a different user.
+ #
+ # If Calamares is running as non-root, though, this is fine.
+ import getpass
+ name = getpass.getuser()
+ if name != "root":
+ return name
+
+ # TODO: other mechanisms, e.g. guessing that "live" is the name
+ # TODO: support a what-is-the-live-user setting
+ return None
+
+
+def replace_username(nm_config_filename, live_user, target_user):
+ """
+ If @p live_user isn't None, then go through the given
+ file and replace @p live_user by the @p target_user.
+
+ Reads the file, then (re-)writes it with new permissions lives.
+ """
+ # FIXME: Perhaps if live_user is None, we should just replace **all**
+ # permissions lines? After all, this is supposed to be a live
+ # system so **whatever** NM networks are configured, should be
+ # available to the new user.
+ if live_user is None:
+ return
+ if not os.path.exists(nm_config_filename):
+ return
+
+ with open(target_network, "r") as network_conf:
+ text = network_conf.readlines()
+
+ live_permissions = 'permissions=user:{}:;'.format(live_user)
+ target_permissions = 'permissions=user:{}:;\n'.format(user)
+ with open(target_network, "w") as network_conf:
+ for line in text:
+ if live_permissions in line:
+ line = target_permissions
+ network_conf.write(line)
+
+
+def path_pair(root_mount_point, relative_path):
+ """
+ Returns /relative_path and the relative path in the target system.
+ """
+ return ("/" + relative_path, os.path.join(root_mount_point, relative_path))
+
+
def run():
"""
Setup network configuration
"""
root_mount_point = libcalamares.globalstorage.value("rootMountPoint")
user = libcalamares.globalstorage.value("username")
- live_user = os.getlogin()
+ live_user = get_live_user()
if root_mount_point is None:
libcalamares.utils.warning("rootMountPoint is empty, {!s}".format(root_mount_point))
return (_("Configuration Error"),
_("No root mount point is given for
{!s}
to use." ).format("networkcfg"))
- source_nm = "/etc/NetworkManager/system-connections/"
- target_nm = os.path.join(
- root_mount_point, "etc/NetworkManager/system-connections/"
- )
+ source_nm, target_nm = path_pair(root_mount_point, "etc/NetworkManager/system-connections/")
# Sanity checks. We don't want to do anything if a network
# configuration already exists on the target
@@ -63,27 +123,16 @@ def run():
try:
shutil.copy(source_network, target_network, follow_symlinks=False)
- if live_user in open(target_network).read():
- text = []
- with open(target_network, "r") as network_conf:
- text = network_conf.readlines()
- with open(target_network, "w") as network_conf:
- for line in text:
- if 'permissions=user:{}:;'.format(live_user) in line:
- line = 'permissions=user:{}:;\n'.format(user)
- network_conf.write(line)
- network_conf.close()
+ replace_username(target_network, live_user, user)
except FileNotFoundError:
libcalamares.utils.debug(
- "Can't copy network configuration files in "
- + "{}".format(source_network)
+ "Can't copy network configuration files in {}".format(source_network)
)
except FileExistsError:
pass
# We need to overwrite the default resolv.conf in the chroot.
- source_resolv = "/etc/resolv.conf"
- target_resolv = os.path.join(root_mount_point, "etc/resolv.conf")
+ source_resolv, target_resolv = path_pair(root_mount_point, "etc/resolv.conf")
if source_resolv != target_resolv and os.path.exists(source_resolv):
try:
os.remove(target_resolv)
diff --git a/src/modules/partition/core/PartUtils.cpp b/src/modules/partition/core/PartUtils.cpp
index 54f971f4e..806c0ceb3 100644
--- a/src/modules/partition/core/PartUtils.cpp
+++ b/src/modules/partition/core/PartUtils.cpp
@@ -126,23 +126,22 @@ canBeResized( Partition* candidate, const Logger::Once& o )
return false;
}
- cDebug() << o << "Checking if" << convenienceName( candidate ) << "can be resized.";
if ( !candidate->fileSystem().supportGrow() || !candidate->fileSystem().supportShrink() )
{
- cDebug() << Logger::SubEntry << "NO, filesystem" << candidate->fileSystem().name()
- << "does not support resize.";
+ cDebug() << o << "Can not resize" << convenienceName( candidate ) << ", filesystem"
+ << candidate->fileSystem().name() << "does not support resize.";
return false;
}
if ( isPartitionFreeSpace( candidate ) )
{
- cDebug() << Logger::SubEntry << "NO, partition is free space";
+ cDebug() << o << "Can not resize" << convenienceName( candidate ) << ", partition is free space";
return false;
}
if ( candidate->isMounted() )
{
- cDebug() << Logger::SubEntry << "NO, partition is mounted";
+ cDebug() << o << "Can not resize" << convenienceName( candidate ) << ", partition is mounted";
return false;
}
@@ -151,14 +150,14 @@ canBeResized( Partition* candidate, const Logger::Once& o )
PartitionTable* table = dynamic_cast< PartitionTable* >( candidate->parent() );
if ( !table )
{
- cDebug() << Logger::SubEntry << "NO, no partition table found";
+ cDebug() << o << "Can not resize" << convenienceName( candidate ) << ", no partition table found";
return false;
}
if ( table->numPrimaries() >= table->maxPrimaries() )
{
- cDebug() << Logger::SubEntry << "NO, partition table already has" << table->maxPrimaries()
- << "primary partitions.";
+ cDebug() << o << "Can not resize" << convenienceName( candidate ) << ", partition table already has"
+ << table->maxPrimaries() << "primary partitions.";
return false;
}
}
@@ -167,7 +166,8 @@ canBeResized( Partition* candidate, const Logger::Once& o )
double requiredStorageGiB = getRequiredStorageGiB( ok );
if ( !ok )
{
- cDebug() << Logger::SubEntry << "NO, requiredStorageGiB is not set correctly.";
+ cDebug() << o << "Can not resize" << convenienceName( candidate )
+ << ", requiredStorageGiB is not set correctly.";
return false;
}
@@ -200,24 +200,25 @@ canBeResized( Partition* candidate, const Logger::Once& o )
bool
canBeResized( DeviceModel* dm, const QString& partitionPath, const Logger::Once& o )
{
- cDebug() << o << "Checking if" << partitionPath << "can be resized.";
- QString partitionWithOs = partitionPath;
- if ( partitionWithOs.startsWith( "/dev/" ) )
+ if ( partitionPath.startsWith( "/dev/" ) )
{
for ( int i = 0; i < dm->rowCount(); ++i )
{
Device* dev = dm->deviceForIndex( dm->index( i ) );
- Partition* candidate = CalamaresUtils::Partition::findPartitionByPath( { dev }, partitionWithOs );
+ Partition* candidate = CalamaresUtils::Partition::findPartitionByPath( { dev }, partitionPath );
if ( candidate )
{
return canBeResized( candidate, o );
}
}
- cDebug() << Logger::SubEntry << "no Partition* found for" << partitionWithOs;
+ cWarning() << "Can not resize" << partitionPath << ", no Partition* found.";
+ return false;
+ }
+ else
+ {
+ cWarning() << "Can not resize" << partitionPath << ", does not start with /dev";
+ return false;
}
-
- cDebug() << Logger::SubEntry << "Partition" << partitionWithOs << "CANNOT BE RESIZED FOR AUTOINSTALL.";
- return false;
}
@@ -250,8 +251,6 @@ lookForFstabEntries( const QString& partitionPath )
{
QFile fstabFile( mount.path() + "/etc/fstab" );
- cDebug() << Logger::SubEntry << "reading" << fstabFile.fileName();
-
if ( fstabFile.open( QIODevice::ReadOnly | QIODevice::Text ) )
{
const QStringList fstabLines = QString::fromLocal8Bit( fstabFile.readAll() ).split( '\n' );
@@ -261,10 +260,11 @@ lookForFstabEntries( const QString& partitionPath )
fstabEntries.append( FstabEntry::fromEtcFstab( rawLine ) );
}
fstabFile.close();
- cDebug() << Logger::SubEntry << "got" << fstabEntries.count() << "lines.";
+ const int lineCount = fstabEntries.count();
std::remove_if(
fstabEntries.begin(), fstabEntries.end(), []( const FstabEntry& x ) { return !x.isValid(); } );
- cDebug() << Logger::SubEntry << "got" << fstabEntries.count() << "fstab entries.";
+ cDebug() << Logger::SubEntry << "got" << fstabEntries.count() << "fstab entries from" << lineCount
+ << "lines in" << fstabFile.fileName();
}
else
{
@@ -529,7 +529,7 @@ efiFilesystemMinimumSize()
QString
canonicalFilesystemName( const QString& fsName, FileSystem::Type* fsType )
{
- cPointerSetter type( fsType );
+ cScopedAssignment type( fsType );
if ( fsName.isEmpty() )
{
type = FileSystem::Ext4;