[users] Add a template for hostname suggestion
This commit is contained in:
parent
1a8fc1feec
commit
b95eb55994
@ -20,6 +20,8 @@
|
|||||||
#include "utils/String.h"
|
#include "utils/String.h"
|
||||||
#include "utils/Variant.h"
|
#include "utils/Variant.h"
|
||||||
|
|
||||||
|
#include <KMacroExpander>
|
||||||
|
|
||||||
#include <QCoreApplication>
|
#include <QCoreApplication>
|
||||||
#include <QFile>
|
#include <QFile>
|
||||||
#include <QMetaProperty>
|
#include <QMetaProperty>
|
||||||
@ -305,6 +307,12 @@ Config::hostnameStatus() const
|
|||||||
return QString();
|
return QString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static QString
|
||||||
|
cleanupForHostname( const QString& s )
|
||||||
|
{
|
||||||
|
QRegExp dmirx( "[^a-zA-Z0-9]", Qt::CaseInsensitive );
|
||||||
|
return s.toLower().replace( dmirx, " " ).remove( ' ' );
|
||||||
|
}
|
||||||
|
|
||||||
/** @brief Guess the machine's name
|
/** @brief Guess the machine's name
|
||||||
*
|
*
|
||||||
@ -319,16 +327,11 @@ guessProductName()
|
|||||||
|
|
||||||
if ( !tried )
|
if ( !tried )
|
||||||
{
|
{
|
||||||
// yes validateHostnameText() but these files can be a mess
|
|
||||||
QRegExp dmirx( "[^a-zA-Z0-9]", Qt::CaseInsensitive );
|
|
||||||
QFile dmiFile( QStringLiteral( "/sys/devices/virtual/dmi/id/product_name" ) );
|
QFile dmiFile( QStringLiteral( "/sys/devices/virtual/dmi/id/product_name" ) );
|
||||||
|
|
||||||
if ( dmiFile.exists() && dmiFile.open( QIODevice::ReadOnly ) )
|
if ( dmiFile.exists() && dmiFile.open( QIODevice::ReadOnly ) )
|
||||||
{
|
{
|
||||||
dmiProduct = QString::fromLocal8Bit( dmiFile.readAll().simplified().data() )
|
dmiProduct = cleanupForHostname( QString::fromLocal8Bit( dmiFile.readAll().simplified().data() ) );
|
||||||
.toLower()
|
|
||||||
.replace( dmirx, " " )
|
|
||||||
.remove( ' ' );
|
|
||||||
}
|
}
|
||||||
if ( dmiProduct.isEmpty() )
|
if ( dmiProduct.isEmpty() )
|
||||||
{
|
{
|
||||||
@ -386,17 +389,37 @@ makeLoginNameSuggestion( const QStringList& parts )
|
|||||||
return USERNAME_RX.indexIn( usernameSuggestion ) != -1 ? usernameSuggestion : QString();
|
return USERNAME_RX.indexIn( usernameSuggestion ) != -1 ? usernameSuggestion : QString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @brief Return an invalid string for use in a hostname, if @p s is empty
|
||||||
|
*
|
||||||
|
* Maps empty to "^" (which is invalid in a hostname), everything else
|
||||||
|
* returns @p s itself.
|
||||||
|
*/
|
||||||
static QString
|
static QString
|
||||||
makeHostnameSuggestion( const QStringList& parts )
|
invalidEmpty( const QString& s )
|
||||||
{
|
{
|
||||||
static const QRegExp HOSTNAME_RX( "^[a-zA-Z0-9][-a-zA-Z0-9_]*$" );
|
return s.isEmpty() ? QStringLiteral( "^" ) : s;
|
||||||
if ( parts.isEmpty() || parts.first().isEmpty() )
|
}
|
||||||
{
|
|
||||||
return QString();
|
|
||||||
}
|
|
||||||
|
|
||||||
QString productName = guessProductName();
|
STATICTEST QString
|
||||||
QString hostnameSuggestion = QStringLiteral( "%1-%2" ).arg( parts.first() ).arg( productName );
|
makeHostnameSuggestion( const QString& templateString, const QStringList& fullNameParts, const QString& loginName )
|
||||||
|
{
|
||||||
|
QHash< QString, QString > replace;
|
||||||
|
// User data
|
||||||
|
replace.insert( QStringLiteral( "first" ),
|
||||||
|
invalidEmpty( fullNameParts.isEmpty() ? QString() : cleanupForHostname( fullNameParts.first() ) ) );
|
||||||
|
replace.insert( QStringLiteral( "name" ), invalidEmpty( cleanupForHostname( fullNameParts.join( QString() ) ) ) );
|
||||||
|
replace.insert( QStringLiteral( "login" ), invalidEmpty( cleanupForHostname( loginName ) ) );
|
||||||
|
// Hardware data
|
||||||
|
replace.insert( QStringLiteral( "product" ), guessProductName() );
|
||||||
|
replace.insert( QStringLiteral( "product2" ), cleanupForHostname( QSysInfo::prettyProductName() ) );
|
||||||
|
replace.insert( QStringLiteral( "cpu" ), cleanupForHostname( QSysInfo::currentCpuArchitecture() ) );
|
||||||
|
// Hostname data
|
||||||
|
replace.insert( QStringLiteral( "host" ), invalidEmpty( cleanupForHostname( QSysInfo::machineHostName() ) ) );
|
||||||
|
|
||||||
|
QString hostnameSuggestion = KMacroExpander::expandMacros( templateString, replace, '$' );
|
||||||
|
|
||||||
|
// RegExp for valid hostnames; if the suggestion produces a valid name, return it
|
||||||
|
static const QRegExp HOSTNAME_RX( "^[a-zA-Z0-9][-a-zA-Z0-9_]*$" );
|
||||||
return HOSTNAME_RX.indexIn( hostnameSuggestion ) != -1 ? hostnameSuggestion : QString();
|
return HOSTNAME_RX.indexIn( hostnameSuggestion ) != -1 ? hostnameSuggestion : QString();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -427,7 +450,7 @@ Config::setFullName( const QString& name )
|
|||||||
// Build login and hostname, if needed
|
// Build login and hostname, if needed
|
||||||
static QRegExp rx( "[^a-zA-Z0-9 ]", Qt::CaseInsensitive );
|
static QRegExp rx( "[^a-zA-Z0-9 ]", Qt::CaseInsensitive );
|
||||||
|
|
||||||
QString cleanName = CalamaresUtils::removeDiacritics( transliterate( name ) )
|
const QString cleanName = CalamaresUtils::removeDiacritics( transliterate( name ) )
|
||||||
.replace( QRegExp( "[-']" ), "" )
|
.replace( QRegExp( "[-']" ), "" )
|
||||||
.replace( rx, " " )
|
.replace( rx, " " )
|
||||||
.toLower()
|
.toLower()
|
||||||
@ -438,7 +461,7 @@ Config::setFullName( const QString& name )
|
|||||||
|
|
||||||
if ( !m_customLoginName )
|
if ( !m_customLoginName )
|
||||||
{
|
{
|
||||||
QString login = makeLoginNameSuggestion( cleanParts );
|
const QString login = makeLoginNameSuggestion( cleanParts );
|
||||||
if ( !login.isEmpty() && login != m_loginName )
|
if ( !login.isEmpty() && login != m_loginName )
|
||||||
{
|
{
|
||||||
setLoginName( login );
|
setLoginName( login );
|
||||||
@ -448,7 +471,7 @@ Config::setFullName( const QString& name )
|
|||||||
}
|
}
|
||||||
if ( !m_customHostName )
|
if ( !m_customHostName )
|
||||||
{
|
{
|
||||||
QString hostname = makeHostnameSuggestion( cleanParts );
|
const QString hostname = makeHostnameSuggestion( m_hostnameTemplate, cleanParts, loginName() );
|
||||||
if ( !hostname.isEmpty() && hostname != m_hostname )
|
if ( !hostname.isEmpty() && hostname != m_hostname )
|
||||||
{
|
{
|
||||||
setHostName( hostname );
|
setHostName( hostname );
|
||||||
@ -877,6 +900,8 @@ Config::setConfigurationMap( const QVariantMap& configurationMap )
|
|||||||
copyLegacy( configurationMap, "writeHostsFile", hostnameSettings, "writeHostsFile" );
|
copyLegacy( configurationMap, "writeHostsFile", hostnameSettings, "writeHostsFile" );
|
||||||
m_hostnameAction = getHostNameAction( hostnameSettings );
|
m_hostnameAction = getHostNameAction( hostnameSettings );
|
||||||
m_writeEtcHosts = CalamaresUtils::getBool( hostnameSettings, "writeHostsFile", true );
|
m_writeEtcHosts = CalamaresUtils::getBool( hostnameSettings, "writeHostsFile", true );
|
||||||
|
m_hostnameTemplate
|
||||||
|
= CalamaresUtils::getString( hostnameSettings, "template", QStringLiteral( "${first}-${product}" ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
setConfigurationDefaultGroups( configurationMap, m_defaultGroups );
|
setConfigurationDefaultGroups( configurationMap, m_defaultGroups );
|
||||||
|
@ -345,6 +345,8 @@ private:
|
|||||||
|
|
||||||
HostNameAction m_hostnameAction = HostNameAction::EtcHostname;
|
HostNameAction m_hostnameAction = HostNameAction::EtcHostname;
|
||||||
bool m_writeEtcHosts = false;
|
bool m_writeEtcHosts = false;
|
||||||
|
QString m_hostnameTemplate;
|
||||||
|
|
||||||
PasswordCheckList m_passwordChecks;
|
PasswordCheckList m_passwordChecks;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -19,6 +19,8 @@
|
|||||||
extern void setConfigurationDefaultGroups( const QVariantMap& map, QList< GroupDescription >& defaultGroups );
|
extern void setConfigurationDefaultGroups( const QVariantMap& map, QList< GroupDescription >& defaultGroups );
|
||||||
extern HostNameAction getHostNameAction( const QVariantMap& configurationMap );
|
extern HostNameAction getHostNameAction( const QVariantMap& configurationMap );
|
||||||
extern bool addPasswordCheck( const QString& key, const QVariant& value, PasswordCheckList& passwordChecks );
|
extern bool addPasswordCheck( const QString& key, const QVariant& value, PasswordCheckList& passwordChecks );
|
||||||
|
extern QString
|
||||||
|
makeHostnameSuggestion( const QString& templateString, const QStringList& fullNameParts, const QString& loginName );
|
||||||
|
|
||||||
/** @brief Test Config object methods and internals
|
/** @brief Test Config object methods and internals
|
||||||
*
|
*
|
||||||
@ -43,6 +45,9 @@ private Q_SLOTS:
|
|||||||
void testHostActions_data();
|
void testHostActions_data();
|
||||||
void testHostActions();
|
void testHostActions();
|
||||||
void testHostActions2();
|
void testHostActions2();
|
||||||
|
void testHostSuggestions_data();
|
||||||
|
void testHostSuggestions();
|
||||||
|
|
||||||
void testPasswordChecks();
|
void testPasswordChecks();
|
||||||
void testUserPassword();
|
void testUserPassword();
|
||||||
|
|
||||||
@ -279,6 +284,34 @@ UserTests::testHostActions2()
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
UserTests::testHostSuggestions_data()
|
||||||
|
{
|
||||||
|
QTest::addColumn< QString >( "templateString" );
|
||||||
|
QTest::addColumn< QString >( "result" );
|
||||||
|
|
||||||
|
QTest::newRow( "unset " ) << QString() << QString();
|
||||||
|
QTest::newRow( "const " ) << QStringLiteral( "derp" ) << QStringLiteral( "derp" );
|
||||||
|
QTest::newRow( "escaped" ) << QStringLiteral( "$$" ) << QString(); // Because invalid
|
||||||
|
QTest::newRow( "default" ) << QStringLiteral( "${first}-pc" )
|
||||||
|
<< QStringLiteral( "chuck-pc" ); // Avoid ${product} because it's DMI-based
|
||||||
|
QTest::newRow( "full " ) << QStringLiteral( "${name}" ) << QStringLiteral( "chuckyeager" );
|
||||||
|
QTest::newRow( "login+ " ) << QStringLiteral( "${login}-${first}" ) << QStringLiteral( "bill-chuck" );
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
UserTests::testHostSuggestions()
|
||||||
|
{
|
||||||
|
const QStringList fullName { "Chuck", "Yeager" };
|
||||||
|
const QString login { "bill" };
|
||||||
|
|
||||||
|
QFETCH( QString, templateString );
|
||||||
|
QFETCH( QString, result );
|
||||||
|
|
||||||
|
QCOMPARE( makeHostnameSuggestion( templateString, fullName, login ), result );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
UserTests::testPasswordChecks()
|
UserTests::testPasswordChecks()
|
||||||
{
|
{
|
||||||
|
Loading…
Reference in New Issue
Block a user