From 7ec7278fd388faef2732a01e389dbf12e1f94440 Mon Sep 17 00:00:00 2001 From: Adriaan de Groot Date: Tue, 30 Apr 2019 16:47:10 -0400 Subject: [PATCH 01/31] [libcalamares] [locale] Move GeoIP code to the library --- src/{modules/locale => libcalamares/geoip}/GeoIP.cpp | 0 src/{modules/locale => libcalamares/geoip}/GeoIP.h | 0 src/{modules/locale => libcalamares/geoip}/GeoIPJSON.cpp | 0 src/{modules/locale => libcalamares/geoip}/GeoIPJSON.h | 0 src/{modules/locale => libcalamares/geoip}/GeoIPTests.cpp | 0 src/{modules/locale => libcalamares/geoip}/GeoIPTests.h | 0 src/{modules/locale => libcalamares/geoip}/GeoIPXML.cpp | 0 src/{modules/locale => libcalamares/geoip}/GeoIPXML.h | 0 src/{modules/locale => libcalamares/geoip}/test_geoip.cpp | 0 9 files changed, 0 insertions(+), 0 deletions(-) rename src/{modules/locale => libcalamares/geoip}/GeoIP.cpp (100%) rename src/{modules/locale => libcalamares/geoip}/GeoIP.h (100%) rename src/{modules/locale => libcalamares/geoip}/GeoIPJSON.cpp (100%) rename src/{modules/locale => libcalamares/geoip}/GeoIPJSON.h (100%) rename src/{modules/locale => libcalamares/geoip}/GeoIPTests.cpp (100%) rename src/{modules/locale => libcalamares/geoip}/GeoIPTests.h (100%) rename src/{modules/locale => libcalamares/geoip}/GeoIPXML.cpp (100%) rename src/{modules/locale => libcalamares/geoip}/GeoIPXML.h (100%) rename src/{modules/locale => libcalamares/geoip}/test_geoip.cpp (100%) diff --git a/src/modules/locale/GeoIP.cpp b/src/libcalamares/geoip/GeoIP.cpp similarity index 100% rename from src/modules/locale/GeoIP.cpp rename to src/libcalamares/geoip/GeoIP.cpp diff --git a/src/modules/locale/GeoIP.h b/src/libcalamares/geoip/GeoIP.h similarity index 100% rename from src/modules/locale/GeoIP.h rename to src/libcalamares/geoip/GeoIP.h diff --git a/src/modules/locale/GeoIPJSON.cpp b/src/libcalamares/geoip/GeoIPJSON.cpp similarity index 100% rename from src/modules/locale/GeoIPJSON.cpp rename to src/libcalamares/geoip/GeoIPJSON.cpp diff --git a/src/modules/locale/GeoIPJSON.h b/src/libcalamares/geoip/GeoIPJSON.h similarity index 100% rename from src/modules/locale/GeoIPJSON.h rename to src/libcalamares/geoip/GeoIPJSON.h diff --git a/src/modules/locale/GeoIPTests.cpp b/src/libcalamares/geoip/GeoIPTests.cpp similarity index 100% rename from src/modules/locale/GeoIPTests.cpp rename to src/libcalamares/geoip/GeoIPTests.cpp diff --git a/src/modules/locale/GeoIPTests.h b/src/libcalamares/geoip/GeoIPTests.h similarity index 100% rename from src/modules/locale/GeoIPTests.h rename to src/libcalamares/geoip/GeoIPTests.h diff --git a/src/modules/locale/GeoIPXML.cpp b/src/libcalamares/geoip/GeoIPXML.cpp similarity index 100% rename from src/modules/locale/GeoIPXML.cpp rename to src/libcalamares/geoip/GeoIPXML.cpp diff --git a/src/modules/locale/GeoIPXML.h b/src/libcalamares/geoip/GeoIPXML.h similarity index 100% rename from src/modules/locale/GeoIPXML.h rename to src/libcalamares/geoip/GeoIPXML.h diff --git a/src/modules/locale/test_geoip.cpp b/src/libcalamares/geoip/test_geoip.cpp similarity index 100% rename from src/modules/locale/test_geoip.cpp rename to src/libcalamares/geoip/test_geoip.cpp From 9ed46fc275799266e0496aec2015fd2519bd5115 Mon Sep 17 00:00:00 2001 From: Adriaan de Groot Date: Tue, 30 Apr 2019 16:53:26 -0400 Subject: [PATCH 02/31] [libcalamares] [locale] Adjust CMakeLists to moved code --- src/libcalamares/CMakeLists.txt | 34 ++++++++++++++++++++++++++++++- src/modules/locale/CMakeLists.txt | 30 --------------------------- 2 files changed, 33 insertions(+), 31 deletions(-) diff --git a/src/libcalamares/CMakeLists.txt b/src/libcalamares/CMakeLists.txt index 4aa7c44df..7ef9843b9 100644 --- a/src/libcalamares/CMakeLists.txt +++ b/src/libcalamares/CMakeLists.txt @@ -69,7 +69,20 @@ if( WITH_PYTHON ) ) endif() -add_library( calamares SHARED ${libSources} ${kdsagSources} ${utilsSources} ) +set( geoipSources + geoip/GeoIP.cpp + geoip/GeoIPJSON.cpp +) +set( geoip_libs ) + +find_package(Qt5 COMPONENTS Xml) +if( Qt5Xml_FOUND ) + list( APPEND geoipSources geoip/GeoIPXML.cpp ) + list( APPEND geoip_libs Qt5::Network Qt5::Xml ) + add_definitions( -DHAVE_XML ) +endif() + +add_library( calamares SHARED ${libSources} ${kdsagSources} ${utilsSources} ${geoipSources} ) set_target_properties( calamares PROPERTIES VERSION ${CALAMARES_VERSION_SHORT} @@ -82,6 +95,7 @@ target_link_libraries( calamares ${OPTIONAL_PRIVATE_LIBRARIES} LINK_PUBLIC ${YAMLCPP_LIBRARY} + ${geoip_libs} Qt5::Core ) @@ -103,6 +117,24 @@ if ( ECM_FOUND AND BUILD_TESTING ) Qt5::Test ) calamares_automoc( libcalamarestest ) + + ecm_add_test( + geoip/GeoIPTests.cpp + ${geoip_src} + TEST_NAME + geoiptest + LINK_LIBRARIES + calamares + Qt5::Test + ${YAMLCPP_LIBRARY} + ) + calamares_automoc( geoiptest ) +endif() + +if( BUILD_TESTING ) + add_executable( test_geoip geoip/test_geoip.cpp ${geoip_src} ) + target_link_libraries( test_geoip calamares Qt5::Network ${YAMLCPP_LIBRARY} ) + calamares_automoc( test_geoip ) endif() # Make symlink lib/calamares/libcalamares.so to lib/libcalamares.so.VERSION so diff --git a/src/modules/locale/CMakeLists.txt b/src/modules/locale/CMakeLists.txt index affaa3753..768a67543 100644 --- a/src/modules/locale/CMakeLists.txt +++ b/src/modules/locale/CMakeLists.txt @@ -8,16 +8,6 @@ endif() include_directories( ${PROJECT_BINARY_DIR}/src/libcalamaresui ) -set( geoip_src GeoIP.cpp GeoIPJSON.cpp ) -set( geoip_libs ) - -find_package(Qt5 COMPONENTS Xml) -if( Qt5Xml_FOUND ) - list( APPEND geoip_src GeoIPXML.cpp ) - list( APPEND geoip_libs Qt5::Xml ) - add_definitions( -DHAVE_XML ) -endif() - calamares_add_plugin( locale TYPE viewmodule EXPORT_MACRO PLUGINDLLEXPORT_PRO @@ -42,20 +32,6 @@ calamares_add_plugin( locale ) if( ECM_FOUND AND BUILD_TESTING ) - ecm_add_test( - GeoIPTests.cpp - ${geoip_src} - TEST_NAME - geoiptest - LINK_LIBRARIES - calamaresui - Qt5::Network - Qt5::Test - ${geoip_libs} - ${YAMLCPP_LIBRARY} - ) - calamares_automoc( geoiptest ) - ecm_add_test( Tests.cpp LocaleConfiguration.cpp @@ -67,9 +43,3 @@ if( ECM_FOUND AND BUILD_TESTING ) ) calamares_automoc( localetest ) endif() - -if( BUILD_TESTING ) - add_executable( test_geoip test_geoip.cpp ${geoip_src} ) - target_link_libraries( test_geoip calamaresui Qt5::Network ${geoip_libs} ${YAMLCPP_LIBRARY} ) - calamares_automoc( test_geoip ) -endif() From a1b1ebcd29fc0e6b8c1e0b892a07a44a281b1616 Mon Sep 17 00:00:00 2001 From: Adriaan de Groot Date: Wed, 1 May 2019 06:31:31 -0400 Subject: [PATCH 03/31] [locale] Compile with moved GeoIP handling --- src/modules/locale/LocaleViewStep.cpp | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/src/modules/locale/LocaleViewStep.cpp b/src/modules/locale/LocaleViewStep.cpp index d321b8501..104abbfc2 100644 --- a/src/modules/locale/LocaleViewStep.cpp +++ b/src/modules/locale/LocaleViewStep.cpp @@ -19,18 +19,19 @@ #include "LocaleViewStep.h" -#include "GeoIP.h" -#include "GeoIPJSON.h" -#ifdef HAVE_XML -#include "GeoIPXML.h" -#endif -#include "GlobalStorage.h" -#include "JobQueue.h" #include "LocalePage.h" - #include "timezonewidget/localeglobal.h" #include "widgets/WaitingWidget.h" +#include "GlobalStorage.h" +#include "JobQueue.h" + +#include "geoip/GeoIP.h" +#include "geoip/GeoIPJSON.h" +#ifdef HAVE_XML +#include "geoip/GeoIPXML.h" +#endif + #include "utils/CalamaresUtilsGui.h" #include "utils/Logger.h" #include "utils/Variant.h" From ce909f00cc125d4bb58860295590dcce01afd168 Mon Sep 17 00:00:00 2001 From: Adriaan de Groot Date: Wed, 1 May 2019 06:39:20 -0400 Subject: [PATCH 04/31] [libcalamares] Drop unnecessary HAVE_XML - Linking to QtXml gives us a -DQT_XML_LIB already, so use that. --- src/libcalamares/CMakeLists.txt | 1 - src/libcalamares/geoip/GeoIPTests.cpp | 12 ++++++------ src/libcalamares/geoip/test_geoip.cpp | 4 ++-- src/modules/locale/LocaleViewStep.cpp | 4 ++-- 4 files changed, 10 insertions(+), 11 deletions(-) diff --git a/src/libcalamares/CMakeLists.txt b/src/libcalamares/CMakeLists.txt index 7ef9843b9..ae702a8b3 100644 --- a/src/libcalamares/CMakeLists.txt +++ b/src/libcalamares/CMakeLists.txt @@ -79,7 +79,6 @@ find_package(Qt5 COMPONENTS Xml) if( Qt5Xml_FOUND ) list( APPEND geoipSources geoip/GeoIPXML.cpp ) list( APPEND geoip_libs Qt5::Network Qt5::Xml ) - add_definitions( -DHAVE_XML ) endif() add_library( calamares SHARED ${libSources} ${kdsagSources} ${utilsSources} ${geoipSources} ) diff --git a/src/libcalamares/geoip/GeoIPTests.cpp b/src/libcalamares/geoip/GeoIPTests.cpp index af114611e..9a8070148 100644 --- a/src/libcalamares/geoip/GeoIPTests.cpp +++ b/src/libcalamares/geoip/GeoIPTests.cpp @@ -19,7 +19,7 @@ #include "GeoIPTests.h" #include "GeoIPJSON.h" -#ifdef HAVE_XML +#ifdef QT_XML_LIB #include "GeoIPXML.h" #endif @@ -118,7 +118,7 @@ static const char xml_data_ubiquity[] = void GeoIPTests::testXML() { -#ifdef HAVE_XML +#ifdef QT_XML_LIB GeoIPXML handler; auto tz = handler.processReply( xml_data_ubiquity ); @@ -133,7 +133,7 @@ GeoIPTests::testXML2() static const char data[] = "America/North Dakota/Beulah"; // With a space! -#ifdef HAVE_XML +#ifdef QT_XML_LIB GeoIPXML handler; auto tz = handler.processReply( data ); @@ -145,7 +145,7 @@ GeoIPTests::testXML2() void GeoIPTests::testXMLalt() { -#ifdef HAVE_XML +#ifdef QT_XML_LIB GeoIPXML handler( "ZT" ); auto tz = handler.processReply( "Moon/Dark_side" ); @@ -157,7 +157,7 @@ void GeoIPTests::testXMLalt() void GeoIPTests::testXMLbad() { -#ifdef HAVE_XML +#ifdef QT_XML_LIB GeoIPXML handler; auto tz = handler.processReply( "{time_zone: \"Europe/Paris\"}" ); QCOMPARE( tz.first, QString() ); @@ -249,7 +249,7 @@ void GeoIPTests::testGet() CHECK_GET( JSON, QStringLiteral("Location.TimeZone"), "https://geoip.kde.org/debug" ) // 2-level JSON -#ifdef HAVE_XML +#ifdef QT_XML_LIB CHECK_GET( XML, QString(), "http://geoip.ubuntu.com/lookup" ) // Ubiquity's XML format CHECK_GET( XML, QString(), "https://geoip.kde.org/v1/ubiquity" ) // Temporary KDE service #endif diff --git a/src/libcalamares/geoip/test_geoip.cpp b/src/libcalamares/geoip/test_geoip.cpp index 89c1b6030..8b8c2b0dc 100644 --- a/src/libcalamares/geoip/test_geoip.cpp +++ b/src/libcalamares/geoip/test_geoip.cpp @@ -23,7 +23,7 @@ #include #include "GeoIPJSON.h" -#ifdef HAVE_XML +#ifdef QT_XML_LIB #include "GeoIPXML.h" #endif @@ -40,7 +40,7 @@ int main(int argc, char** argv) GeoIP* handler = nullptr; if ( QStringLiteral( "json" ) == argv[1] ) handler = new GeoIPJSON; -#ifdef HAVE_XML +#ifdef QT_XML_LIB else if ( QStringLiteral( "xml" ) == argv[1] ) handler = new GeoIPXML; #endif diff --git a/src/modules/locale/LocaleViewStep.cpp b/src/modules/locale/LocaleViewStep.cpp index 104abbfc2..eb3d49960 100644 --- a/src/modules/locale/LocaleViewStep.cpp +++ b/src/modules/locale/LocaleViewStep.cpp @@ -28,7 +28,7 @@ #include "geoip/GeoIP.h" #include "geoip/GeoIPJSON.h" -#ifdef HAVE_XML +#ifdef QT_XML_LIB #include "geoip/GeoIPXML.h" #endif @@ -129,7 +129,7 @@ LocaleViewStep::fetchGeoIpTimezone() { handler = new GeoIPJSON( m_geoipSelector ); } -#if defined(HAVE_XML) +#if defined(QT_XML_LIB) else if ( m_geoipStyle == "xml" ) { handler = new GeoIPXML( m_geoipSelector ); From 73a5e7dd62236a2d6e9984312030187bbc70fc37 Mon Sep 17 00:00:00 2001 From: Adriaan de Groot Date: Thu, 2 May 2019 05:58:52 -0400 Subject: [PATCH 05/31] [libcalamares] Put GeoIP in namespace - Use consistent include-guard style - Put things in namespace CalamaresUtils --- src/libcalamares/geoip/GeoIP.cpp | 5 +++++ src/libcalamares/geoip/GeoIP.h | 9 ++++++--- src/libcalamares/geoip/GeoIPJSON.cpp | 5 +++++ src/libcalamares/geoip/GeoIPJSON.h | 9 ++++++--- src/libcalamares/geoip/GeoIPTests.cpp | 4 ++++ src/libcalamares/geoip/GeoIPXML.cpp | 5 +++++ src/libcalamares/geoip/GeoIPXML.h | 9 ++++++--- src/libcalamares/geoip/test_geoip.cpp | 3 +++ src/modules/locale/LocaleViewStep.cpp | 6 ++++++ 9 files changed, 46 insertions(+), 9 deletions(-) diff --git a/src/libcalamares/geoip/GeoIP.cpp b/src/libcalamares/geoip/GeoIP.cpp index 4c031f286..4f2f4ce62 100644 --- a/src/libcalamares/geoip/GeoIP.cpp +++ b/src/libcalamares/geoip/GeoIP.cpp @@ -20,6 +20,9 @@ #include "utils/Logger.h" +namespace CalamaresUtils +{ + GeoIP::GeoIP(const QString& e) : m_element( e ) { @@ -47,3 +50,5 @@ GeoIP::splitTZString( const QString& tz ) return qMakePair( QString(), QString() ); } + +} // namespace diff --git a/src/libcalamares/geoip/GeoIP.h b/src/libcalamares/geoip/GeoIP.h index 41abd2042..bb1f6a8aa 100644 --- a/src/libcalamares/geoip/GeoIP.h +++ b/src/libcalamares/geoip/GeoIP.h @@ -1,6 +1,6 @@ /* === This file is part of Calamares - === * - * Copyright 2018, Adriaan de Groot + * Copyright 2018-2019, 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 @@ -16,8 +16,8 @@ * along with Calamares. If not, see . */ -#ifndef GEOIP_H -#define GEOIP_H +#ifndef GEOIP_GEOIP_H +#define GEOIP_GEOIP_H #include #include @@ -25,6 +25,8 @@ class QByteArray; +namespace CalamaresUtils +{ /** * @brief Interface for GeoIP retrievers. * @@ -67,4 +69,5 @@ protected: QString m_element; // string for selecting from data } ; +} // namespace #endif diff --git a/src/libcalamares/geoip/GeoIPJSON.cpp b/src/libcalamares/geoip/GeoIPJSON.cpp index 8e5cc2e5c..0f33ca37f 100644 --- a/src/libcalamares/geoip/GeoIPJSON.cpp +++ b/src/libcalamares/geoip/GeoIPJSON.cpp @@ -25,6 +25,9 @@ #include +namespace CalamaresUtils +{ + GeoIPJSON::GeoIPJSON(const QString& attribute) : GeoIP( attribute.isEmpty() ? QStringLiteral( "time_zone" ) : attribute ) { @@ -72,3 +75,5 @@ GeoIPJSON::processReply( const QByteArray& data ) return qMakePair( QString(), QString() ); } + +} // namespace diff --git a/src/libcalamares/geoip/GeoIPJSON.h b/src/libcalamares/geoip/GeoIPJSON.h index 3c08f577b..10a38c48d 100644 --- a/src/libcalamares/geoip/GeoIPJSON.h +++ b/src/libcalamares/geoip/GeoIPJSON.h @@ -1,6 +1,6 @@ /* === This file is part of Calamares - === * - * Copyright 2018, Adriaan de Groot + * Copyright 2018-2019, 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 @@ -16,11 +16,13 @@ * along with Calamares. If not, see . */ -#ifndef GEOIPJSON_H -#define GEOIPJSON_H +#ifndef GEOIP_GEOIPJSON_H +#define GEOIP_GEOIPJSON_H #include "GeoIP.h" +namespace CalamaresUtils +{ /** @brief GeoIP lookup for services that return JSON. * * This is the original implementation of GeoIP lookup, @@ -41,4 +43,5 @@ public: virtual RegionZonePair processReply( const QByteArray& ); } ; +} // namespace #endif diff --git a/src/libcalamares/geoip/GeoIPTests.cpp b/src/libcalamares/geoip/GeoIPTests.cpp index 9a8070148..c84eb4713 100644 --- a/src/libcalamares/geoip/GeoIPTests.cpp +++ b/src/libcalamares/geoip/GeoIPTests.cpp @@ -31,6 +31,10 @@ QTEST_GUILESS_MAIN( GeoIPTests ) +using CalamaresUtils::GeoIP; +using CalamaresUtils::GeoIPJSON; +using CalamaresUtils::GeoIPXML; + GeoIPTests::GeoIPTests() { } diff --git a/src/libcalamares/geoip/GeoIPXML.cpp b/src/libcalamares/geoip/GeoIPXML.cpp index bd675c2ef..e32ff42a4 100644 --- a/src/libcalamares/geoip/GeoIPXML.cpp +++ b/src/libcalamares/geoip/GeoIPXML.cpp @@ -23,6 +23,9 @@ #include #include +namespace CalamaresUtils +{ + GeoIPXML::GeoIPXML( const QString& element ) : GeoIP( element.isEmpty() ? QStringLiteral( "TimeZone" ) : element ) { @@ -58,3 +61,5 @@ GeoIPXML::processReply( const QByteArray& data ) return qMakePair( QString(), QString() ); } + +} // namespace diff --git a/src/libcalamares/geoip/GeoIPXML.h b/src/libcalamares/geoip/GeoIPXML.h index bc3f23bec..15c4e1260 100644 --- a/src/libcalamares/geoip/GeoIPXML.h +++ b/src/libcalamares/geoip/GeoIPXML.h @@ -1,6 +1,6 @@ /* === This file is part of Calamares - === * - * Copyright 2018, Adriaan de Groot + * Copyright 2018-2019, 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 @@ -16,11 +16,13 @@ * along with Calamares. If not, see . */ -#ifndef GEOIPXML_H -#define GEOIPXML_H +#ifndef GEOIP_GEOIPXML_H +#define GEOIP_GEOIPXML_H #include "GeoIP.h" +namespace CalamaresUtils +{ /** @brief GeoIP lookup with XML data * * The data is assumed to be in XML format with a @@ -41,4 +43,5 @@ public: virtual RegionZonePair processReply( const QByteArray& ); } ; +} // namespace #endif diff --git a/src/libcalamares/geoip/test_geoip.cpp b/src/libcalamares/geoip/test_geoip.cpp index 8b8c2b0dc..b5e0234df 100644 --- a/src/libcalamares/geoip/test_geoip.cpp +++ b/src/libcalamares/geoip/test_geoip.cpp @@ -28,6 +28,9 @@ #endif using std::cerr; +using CalamaresUtils::GeoIP; +using CalamaresUtils::GeoIPJSON; +using CalamaresUtils::GeoIPXML; int main(int argc, char** argv) { diff --git a/src/modules/locale/LocaleViewStep.cpp b/src/modules/locale/LocaleViewStep.cpp index eb3d49960..a3ff5df91 100644 --- a/src/modules/locale/LocaleViewStep.cpp +++ b/src/modules/locale/LocaleViewStep.cpp @@ -117,6 +117,12 @@ LocaleViewStep::setUpPage() void LocaleViewStep::fetchGeoIpTimezone() { + using CalamaresUtils::GeoIP; + using CalamaresUtils::GeoIPJSON; +#if defined(QT_XML_LIB) + using CalamaresUtils::GeoIPXML; +#endif + QString actualUrl( m_geoipUrl ); GeoIP *handler = nullptr; From 26b61a4ddb99913c5e6ee60e21ef9f9e79ea30ea Mon Sep 17 00:00:00 2001 From: Adriaan de Groot Date: Thu, 2 May 2019 06:16:08 -0400 Subject: [PATCH 06/31] [libcalamares] Make RegionZonePair type stronger - Derive from QPair instead of being QPair - Add isValid() for checking - Convenience constructors --- src/libcalamares/geoip/GeoIP.cpp | 4 ++-- src/libcalamares/geoip/GeoIP.h | 20 +++++++++++++++++++- src/libcalamares/geoip/GeoIPJSON.cpp | 2 +- src/libcalamares/geoip/GeoIPXML.cpp | 4 ++-- 4 files changed, 24 insertions(+), 6 deletions(-) diff --git a/src/libcalamares/geoip/GeoIP.cpp b/src/libcalamares/geoip/GeoIP.cpp index 4f2f4ce62..ec0368172 100644 --- a/src/libcalamares/geoip/GeoIP.cpp +++ b/src/libcalamares/geoip/GeoIP.cpp @@ -45,10 +45,10 @@ GeoIP::splitTZString( const QString& tz ) cDebug() << "GeoIP reporting" << timezoneString; QString region = tzParts.takeFirst(); QString zone = tzParts.join( '/' ); - return qMakePair( region, zone ); + return RegionZonePair( region, zone ); } - return qMakePair( QString(), QString() ); + return RegionZonePair( QString(), QString() ); } } // namespace diff --git a/src/libcalamares/geoip/GeoIP.h b/src/libcalamares/geoip/GeoIP.h index bb1f6a8aa..cc022d2de 100644 --- a/src/libcalamares/geoip/GeoIP.h +++ b/src/libcalamares/geoip/GeoIP.h @@ -37,7 +37,25 @@ namespace CalamaresUtils class GeoIP { public: - using RegionZonePair = QPair; + /** @brief A Region, Zone pair of strings + * + * A GeoIP lookup returns a timezone, which is represented as a Region, + * Zone pair of strings (e.g. "Europe" and "Amsterdam"). Generally, + * pasting the strings back together with a "/" is the right thing to + * do. The Zone **may** contain a "/" (e.g. "Kentucky/Monticello"). + */ + class RegionZonePair : public QPair + { + public: + /** @brief Construct from an existing pair. */ + explicit RegionZonePair( const QPair& p ) : QPair(p) { } + /** @brief Construct from two strings, like qMakePair(). */ + RegionZonePair( const QString& region, const QString& zone ) : QPair( region, zone ) { } + /** @brief An invalid zone pair (empty strings). */ + RegionZonePair() : QPair( QString(), QString() ) { } + + bool isValid() const { return !first.isEmpty(); } + } ; virtual ~GeoIP(); diff --git a/src/libcalamares/geoip/GeoIPJSON.cpp b/src/libcalamares/geoip/GeoIPJSON.cpp index 0f33ca37f..81056c536 100644 --- a/src/libcalamares/geoip/GeoIPJSON.cpp +++ b/src/libcalamares/geoip/GeoIPJSON.cpp @@ -73,7 +73,7 @@ GeoIPJSON::processReply( const QByteArray& data ) CalamaresUtils::explainYamlException( e, data, "GeoIP data"); } - return qMakePair( QString(), QString() ); + return RegionZonePair( QString(), QString() ); } } // namespace diff --git a/src/libcalamares/geoip/GeoIPXML.cpp b/src/libcalamares/geoip/GeoIPXML.cpp index e32ff42a4..64f6545d4 100644 --- a/src/libcalamares/geoip/GeoIPXML.cpp +++ b/src/libcalamares/geoip/GeoIPXML.cpp @@ -52,14 +52,14 @@ GeoIPXML::processReply( const QByteArray& data ) // None of them valid cWarning() << "GeopIP XML had no recognizable timezone"; - return qMakePair( QString(), QString() ); + return RegionZonePair( QString(), QString() ); } else { cWarning() << "GeoIP XML data error:" << domError << "(line" << errorLine << errorColumn << ')'; } - return qMakePair( QString(), QString() ); + return RegionZonePair( QString(), QString() ); } } // namespace From 16413e7bdb5b26847a74dc1a111e022cfa79f120 Mon Sep 17 00:00:00 2001 From: Adriaan de Groot Date: Thu, 2 May 2019 06:55:41 -0400 Subject: [PATCH 07/31] [libcalamares] Stub GeoIPHandler - The handler class should deal with configuration and query --- src/libcalamares/CMakeLists.txt | 1 + src/libcalamares/geoip/GeoIPHandler.cpp | 40 +++++++++++++++++++++ src/libcalamares/geoip/GeoIPHandler.h | 47 +++++++++++++++++++++++++ 3 files changed, 88 insertions(+) create mode 100644 src/libcalamares/geoip/GeoIPHandler.cpp create mode 100644 src/libcalamares/geoip/GeoIPHandler.h diff --git a/src/libcalamares/CMakeLists.txt b/src/libcalamares/CMakeLists.txt index ae702a8b3..d1dbd81b2 100644 --- a/src/libcalamares/CMakeLists.txt +++ b/src/libcalamares/CMakeLists.txt @@ -71,6 +71,7 @@ endif() set( geoipSources geoip/GeoIP.cpp + geoip/GeoIPHandler.cpp geoip/GeoIPJSON.cpp ) set( geoip_libs ) diff --git a/src/libcalamares/geoip/GeoIPHandler.cpp b/src/libcalamares/geoip/GeoIPHandler.cpp new file mode 100644 index 000000000..87aa1cc24 --- /dev/null +++ b/src/libcalamares/geoip/GeoIPHandler.cpp @@ -0,0 +1,40 @@ +/* === This file is part of Calamares - === + * + * Copyright 2019, 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 "GeoIPHandler.h" + +namespace CalamaresUtils +{ + +GeoIPHandler::GeoIPHandler() +{ +} + +bool +GeoIPHandler::isValid() const +{ + return false; +} + +GeoIP::RegionZonePair +GeoIPHandler::query() const +{ + return GeoIP::RegionZonePair(); +} + +} // namespace diff --git a/src/libcalamares/geoip/GeoIPHandler.h b/src/libcalamares/geoip/GeoIPHandler.h new file mode 100644 index 000000000..92b35eecf --- /dev/null +++ b/src/libcalamares/geoip/GeoIPHandler.h @@ -0,0 +1,47 @@ +/* === This file is part of Calamares - === + * + * Copyright 2019, 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 GEOIP_GEOIPHANDLER_H +#define GEOIP_GEOIPHANDLER_H + +#include "GeoIP.h" + +namespace CalamaresUtils +{ + +/** @brief Handle one complete GeoIP lookup. + * + * This class handles one complete GeoIP lookup. Create it with + * suitable configuration values, then call lookup(). This is a + * synchronous API and will return an invalid zone pair on + * error or if the configuration is not understood/ + */ +class GeoIPHandler +{ +public: + /** @brief An unconfigured handler; this always returns errors. */ + GeoIPHandler(); + + GeoIP::RegionZonePair query() const; + + bool isValid() const; +}; + +} // namespace +#endif + From 9bc8d288002ce3f611d45f381288686b69b25a69 Mon Sep 17 00:00:00 2001 From: Adriaan de Groot Date: Thu, 2 May 2019 07:25:48 -0400 Subject: [PATCH 08/31] [libcalamares] Shuffle GeoIP into a namespace - Use CalamaresUtils::GeoIP for GeoIP code - Name the public interface parts generically, while the implementation details retain GeoIP names. --- src/libcalamares/CMakeLists.txt | 10 +-- src/libcalamares/geoip/GeoIPJSON.cpp | 4 +- src/libcalamares/geoip/GeoIPJSON.h | 8 +- src/libcalamares/geoip/GeoIPTests.cpp | 15 ++-- src/libcalamares/geoip/GeoIPXML.cpp | 4 +- src/libcalamares/geoip/GeoIPXML.h | 8 +- .../geoip/{GeoIPHandler.cpp => Handler.cpp} | 14 ++-- .../geoip/{GeoIPHandler.h => Handler.h} | 15 ++-- .../geoip/{GeoIP.cpp => Interface.cpp} | 12 +-- .../geoip/{GeoIP.h => Interface.h} | 78 ++++++++++--------- src/libcalamares/geoip/test_geoip.cpp | 6 +- src/modules/locale/LocaleViewStep.cpp | 10 +-- 12 files changed, 93 insertions(+), 91 deletions(-) rename src/libcalamares/geoip/{GeoIPHandler.cpp => Handler.cpp} (81%) rename src/libcalamares/geoip/{GeoIPHandler.h => Handler.h} (85%) rename src/libcalamares/geoip/{GeoIP.cpp => Interface.cpp} (88%) rename src/libcalamares/geoip/{GeoIP.h => Interface.h} (52%) diff --git a/src/libcalamares/CMakeLists.txt b/src/libcalamares/CMakeLists.txt index d1dbd81b2..2173c825c 100644 --- a/src/libcalamares/CMakeLists.txt +++ b/src/libcalamares/CMakeLists.txt @@ -70,19 +70,19 @@ if( WITH_PYTHON ) endif() set( geoipSources - geoip/GeoIP.cpp - geoip/GeoIPHandler.cpp - geoip/GeoIPJSON.cpp + geoip/Interface.cpp + geoip/Handler.cpp ) +set( geoipImplementations geoip/GeoIPJSON.cpp ) set( geoip_libs ) find_package(Qt5 COMPONENTS Xml) if( Qt5Xml_FOUND ) - list( APPEND geoipSources geoip/GeoIPXML.cpp ) + list( APPEND geoipImplementations geoip/GeoIPXML.cpp ) list( APPEND geoip_libs Qt5::Network Qt5::Xml ) endif() -add_library( calamares SHARED ${libSources} ${kdsagSources} ${utilsSources} ${geoipSources} ) +add_library( calamares SHARED ${libSources} ${kdsagSources} ${utilsSources} ${geoipSources} ${geoipImplementations} ) set_target_properties( calamares PROPERTIES VERSION ${CALAMARES_VERSION_SHORT} diff --git a/src/libcalamares/geoip/GeoIPJSON.cpp b/src/libcalamares/geoip/GeoIPJSON.cpp index 81056c536..801031c9e 100644 --- a/src/libcalamares/geoip/GeoIPJSON.cpp +++ b/src/libcalamares/geoip/GeoIPJSON.cpp @@ -25,11 +25,11 @@ #include -namespace CalamaresUtils +namespace CalamaresUtils::GeoIP { GeoIPJSON::GeoIPJSON(const QString& attribute) - : GeoIP( attribute.isEmpty() ? QStringLiteral( "time_zone" ) : attribute ) + : Interface( attribute.isEmpty() ? QStringLiteral( "time_zone" ) : attribute ) { } diff --git a/src/libcalamares/geoip/GeoIPJSON.h b/src/libcalamares/geoip/GeoIPJSON.h index 10a38c48d..355fa0739 100644 --- a/src/libcalamares/geoip/GeoIPJSON.h +++ b/src/libcalamares/geoip/GeoIPJSON.h @@ -19,9 +19,9 @@ #ifndef GEOIP_GEOIPJSON_H #define GEOIP_GEOIPJSON_H -#include "GeoIP.h" +#include "Interface.h" -namespace CalamaresUtils +namespace CalamaresUtils::GeoIP { /** @brief GeoIP lookup for services that return JSON. * @@ -29,8 +29,10 @@ namespace CalamaresUtils * (e.g. using the FreeGeoIP.net service), or similar. * * The data is assumed to be in JSON format with a time_zone attribute. + * + * @note This class is an implementation detail. */ -class GeoIPJSON : public GeoIP +class GeoIPJSON : public Interface { public: /** @brief Configure the attribute name which is selected. diff --git a/src/libcalamares/geoip/GeoIPTests.cpp b/src/libcalamares/geoip/GeoIPTests.cpp index c84eb4713..f72388892 100644 --- a/src/libcalamares/geoip/GeoIPTests.cpp +++ b/src/libcalamares/geoip/GeoIPTests.cpp @@ -31,9 +31,7 @@ QTEST_GUILESS_MAIN( GeoIPTests ) -using CalamaresUtils::GeoIP; -using CalamaresUtils::GeoIPJSON; -using CalamaresUtils::GeoIPXML; +using namespace CalamaresUtils::GeoIP; GeoIPTests::GeoIPTests() { @@ -176,24 +174,25 @@ GeoIPTests::testXMLbad() void GeoIPTests::testSplitTZ() { - auto tz = GeoIP::splitTZString( QStringLiteral("Moon/Dark_side") ); + using namespace CalamaresUtils::GeoIP; + auto tz = splitTZString( QStringLiteral("Moon/Dark_side") ); QCOMPARE( tz.first, QStringLiteral("Moon") ); QCOMPARE( tz.second, QStringLiteral("Dark_side") ); // Some providers return weirdly escaped data - tz = GeoIP::splitTZString( QStringLiteral("America\\/NewYork") ); + tz = splitTZString( QStringLiteral("America\\/NewYork") ); QCOMPARE( tz.first, QStringLiteral("America") ); QCOMPARE( tz.second, QStringLiteral("NewYork") ); // That's not actually the zone name // Check that bogus data fails - tz = GeoIP::splitTZString( QString() ); + tz = splitTZString( QString() ); QCOMPARE( tz.first, QString() ); - tz = GeoIP::splitTZString( QStringLiteral("America.NewYork") ); + tz = splitTZString( QStringLiteral("America.NewYork") ); QCOMPARE( tz.first, QString() ); // Check that three-level is split properly and space is replaced - tz = GeoIP::splitTZString( QStringLiteral("America/North Dakota/Beulah") ); + tz = splitTZString( QStringLiteral("America/North Dakota/Beulah") ); QCOMPARE( tz.first, QStringLiteral("America") ); QCOMPARE( tz.second, QStringLiteral("North_Dakota/Beulah") ); } diff --git a/src/libcalamares/geoip/GeoIPXML.cpp b/src/libcalamares/geoip/GeoIPXML.cpp index 64f6545d4..e67354e1d 100644 --- a/src/libcalamares/geoip/GeoIPXML.cpp +++ b/src/libcalamares/geoip/GeoIPXML.cpp @@ -23,11 +23,11 @@ #include #include -namespace CalamaresUtils +namespace CalamaresUtils::GeoIP { GeoIPXML::GeoIPXML( const QString& element ) - : GeoIP( element.isEmpty() ? QStringLiteral( "TimeZone" ) : element ) + : Interface( element.isEmpty() ? QStringLiteral( "TimeZone" ) : element ) { } diff --git a/src/libcalamares/geoip/GeoIPXML.h b/src/libcalamares/geoip/GeoIPXML.h index 15c4e1260..367c307f8 100644 --- a/src/libcalamares/geoip/GeoIPXML.h +++ b/src/libcalamares/geoip/GeoIPXML.h @@ -19,9 +19,9 @@ #ifndef GEOIP_GEOIPXML_H #define GEOIP_GEOIPXML_H -#include "GeoIP.h" +#include "Interface.h" -namespace CalamaresUtils +namespace CalamaresUtils::GeoIP { /** @brief GeoIP lookup with XML data * @@ -29,8 +29,10 @@ namespace CalamaresUtils * * element, which contains the text (string) for the region/zone. This * format is expected by, e.g. the Ubiquity installer. + * + * @note This class is an implementation detail. */ -class GeoIPXML : public GeoIP +class GeoIPXML : public Interface { public: /** @brief Configure the element tag which is selected. diff --git a/src/libcalamares/geoip/GeoIPHandler.cpp b/src/libcalamares/geoip/Handler.cpp similarity index 81% rename from src/libcalamares/geoip/GeoIPHandler.cpp rename to src/libcalamares/geoip/Handler.cpp index 87aa1cc24..22643d9ac 100644 --- a/src/libcalamares/geoip/GeoIPHandler.cpp +++ b/src/libcalamares/geoip/Handler.cpp @@ -16,25 +16,25 @@ * along with Calamares. If not, see . */ -#include "GeoIPHandler.h" +#include "Handler.h" -namespace CalamaresUtils +namespace CalamaresUtils::GeoIP { -GeoIPHandler::GeoIPHandler() +Handler::Handler() { } bool -GeoIPHandler::isValid() const +Handler::isValid() const { return false; } -GeoIP::RegionZonePair -GeoIPHandler::query() const +RegionZonePair +Handler::query() const { - return GeoIP::RegionZonePair(); + return RegionZonePair(); } } // namespace diff --git a/src/libcalamares/geoip/GeoIPHandler.h b/src/libcalamares/geoip/Handler.h similarity index 85% rename from src/libcalamares/geoip/GeoIPHandler.h rename to src/libcalamares/geoip/Handler.h index 92b35eecf..2e7bed888 100644 --- a/src/libcalamares/geoip/GeoIPHandler.h +++ b/src/libcalamares/geoip/Handler.h @@ -16,12 +16,13 @@ * along with Calamares. If not, see . */ -#ifndef GEOIP_GEOIPHANDLER_H -#define GEOIP_GEOIPHANDLER_H +#ifndef GEOIP_HANDLER_H +#define GEOIP_HANDLER_H -#include "GeoIP.h" +#include "Interface.h" -namespace CalamaresUtils +namespace CalamaresUtils {} +namespace CalamaresUtils::GeoIP { /** @brief Handle one complete GeoIP lookup. @@ -31,13 +32,13 @@ namespace CalamaresUtils * synchronous API and will return an invalid zone pair on * error or if the configuration is not understood/ */ -class GeoIPHandler +class DLLEXPORT Handler { public: /** @brief An unconfigured handler; this always returns errors. */ - GeoIPHandler(); + Handler(); - GeoIP::RegionZonePair query() const; + RegionZonePair query() const; bool isValid() const; }; diff --git a/src/libcalamares/geoip/GeoIP.cpp b/src/libcalamares/geoip/Interface.cpp similarity index 88% rename from src/libcalamares/geoip/GeoIP.cpp rename to src/libcalamares/geoip/Interface.cpp index ec0368172..50aa04683 100644 --- a/src/libcalamares/geoip/GeoIP.cpp +++ b/src/libcalamares/geoip/Interface.cpp @@ -16,24 +16,24 @@ * along with Calamares. If not, see . */ -#include "GeoIP.h" +#include "Interface.h" #include "utils/Logger.h" -namespace CalamaresUtils +namespace CalamaresUtils::GeoIP { -GeoIP::GeoIP(const QString& e) +Interface::Interface(const QString& e) : m_element( e ) { } -GeoIP::~GeoIP() +Interface::~Interface() { } -GeoIP::RegionZonePair -GeoIP::splitTZString( const QString& tz ) +RegionZonePair +splitTZString( const QString& tz ) { QString timezoneString( tz ); timezoneString.remove( '\\' ); diff --git a/src/libcalamares/geoip/GeoIP.h b/src/libcalamares/geoip/Interface.h similarity index 52% rename from src/libcalamares/geoip/GeoIP.h rename to src/libcalamares/geoip/Interface.h index cc022d2de..94c6b3c20 100644 --- a/src/libcalamares/geoip/GeoIP.h +++ b/src/libcalamares/geoip/Interface.h @@ -16,8 +16,10 @@ * along with Calamares. If not, see . */ -#ifndef GEOIP_GEOIP_H -#define GEOIP_GEOIP_H +#ifndef GEOIP_INTERFACE_H +#define GEOIP_INTERFACE_H + +#include "DllMacro.h" #include #include @@ -25,8 +27,41 @@ class QByteArray; -namespace CalamaresUtils +namespace CalamaresUtils {} +namespace CalamaresUtils::GeoIP { +/** @brief A Region, Zone pair of strings + * + * A GeoIP lookup returns a timezone, which is represented as a Region, + * Zone pair of strings (e.g. "Europe" and "Amsterdam"). Generally, + * pasting the strings back together with a "/" is the right thing to + * do. The Zone **may** contain a "/" (e.g. "Kentucky/Monticello"). + */ +class DLLEXPORT RegionZonePair : public QPair +{ +public: + /** @brief Construct from an existing pair. */ + explicit RegionZonePair( const QPair& p ) : QPair(p) { } + /** @brief Construct from two strings, like qMakePair(). */ + RegionZonePair( const QString& region, const QString& zone ) : QPair( region, zone ) { } + /** @brief An invalid zone pair (empty strings). */ + RegionZonePair() : QPair( QString(), QString() ) { } + + bool isValid() const { return !first.isEmpty(); } +} ; + +/** @brief Splits a region/zone string into a pair. + * + * Cleans up the string by removing backslashes (\\) + * since some providers return silly-escaped names. Replaces + * spaces with _ since some providers return human-readable names. + * Splits on the first / in the resulting string, or returns a + * pair of empty QStrings if it can't. (e.g. America/North Dakota/Beulah + * will return "America", "North_Dakota/Beulah"). + */ +DLLEXPORT RegionZonePair +splitTZString( const QString& s ); + /** * @brief Interface for GeoIP retrievers. * @@ -34,30 +69,10 @@ namespace CalamaresUtils * and can handle the data returned from its interpretation of that * configured URL, returning a region and zone. */ -class GeoIP +class DLLEXPORT Interface { public: - /** @brief A Region, Zone pair of strings - * - * A GeoIP lookup returns a timezone, which is represented as a Region, - * Zone pair of strings (e.g. "Europe" and "Amsterdam"). Generally, - * pasting the strings back together with a "/" is the right thing to - * do. The Zone **may** contain a "/" (e.g. "Kentucky/Monticello"). - */ - class RegionZonePair : public QPair - { - public: - /** @brief Construct from an existing pair. */ - explicit RegionZonePair( const QPair& p ) : QPair(p) { } - /** @brief Construct from two strings, like qMakePair(). */ - RegionZonePair( const QString& region, const QString& zone ) : QPair( region, zone ) { } - /** @brief An invalid zone pair (empty strings). */ - RegionZonePair() : QPair( QString(), QString() ) { } - - bool isValid() const { return !first.isEmpty(); } - } ; - - virtual ~GeoIP(); + virtual ~Interface(); /** @brief Handle a (successful) request by interpreting the data. * @@ -70,19 +85,8 @@ public: */ virtual RegionZonePair processReply( const QByteArray& ) = 0; - /** @brief Splits a region/zone string into a pair. - * - * Cleans up the string by removing backslashes (\\) - * since some providers return silly-escaped names. Replaces - * spaces with _ since some providers return human-readable names. - * Splits on the first / in the resulting string, or returns a - * pair of empty QStrings if it can't. (e.g. America/North Dakota/Beulah - * will return "America", "North_Dakota/Beulah"). - */ - static RegionZonePair splitTZString( const QString& s ); - protected: - GeoIP( const QString& e = QString() ); + Interface( const QString& e = QString() ); QString m_element; // string for selecting from data } ; diff --git a/src/libcalamares/geoip/test_geoip.cpp b/src/libcalamares/geoip/test_geoip.cpp index b5e0234df..5f7ab935c 100644 --- a/src/libcalamares/geoip/test_geoip.cpp +++ b/src/libcalamares/geoip/test_geoip.cpp @@ -28,9 +28,7 @@ #endif using std::cerr; -using CalamaresUtils::GeoIP; -using CalamaresUtils::GeoIPJSON; -using CalamaresUtils::GeoIPXML; +using namespace CalamaresUtils::GeoIP; int main(int argc, char** argv) { @@ -40,7 +38,7 @@ int main(int argc, char** argv) return 1; } - GeoIP* handler = nullptr; + Interface* handler = nullptr; if ( QStringLiteral( "json" ) == argv[1] ) handler = new GeoIPJSON; #ifdef QT_XML_LIB diff --git a/src/modules/locale/LocaleViewStep.cpp b/src/modules/locale/LocaleViewStep.cpp index a3ff5df91..6ad73cfbe 100644 --- a/src/modules/locale/LocaleViewStep.cpp +++ b/src/modules/locale/LocaleViewStep.cpp @@ -26,7 +26,7 @@ #include "GlobalStorage.h" #include "JobQueue.h" -#include "geoip/GeoIP.h" +#include "geoip/Interface.h" #include "geoip/GeoIPJSON.h" #ifdef QT_XML_LIB #include "geoip/GeoIPXML.h" @@ -117,14 +117,10 @@ LocaleViewStep::setUpPage() void LocaleViewStep::fetchGeoIpTimezone() { - using CalamaresUtils::GeoIP; - using CalamaresUtils::GeoIPJSON; -#if defined(QT_XML_LIB) - using CalamaresUtils::GeoIPXML; -#endif + using namespace CalamaresUtils::GeoIP; QString actualUrl( m_geoipUrl ); - GeoIP *handler = nullptr; + Interface* handler = nullptr; if ( m_geoipStyle.isEmpty() || m_geoipStyle == "legacy" ) { From 1da580f43d6cf8fc20f07fa1d7d11e28afe40871 Mon Sep 17 00:00:00 2001 From: Adriaan de Groot Date: Thu, 2 May 2019 08:33:29 -0400 Subject: [PATCH 09/31] [libcalamares] Implement Handler's synchronous query() - Steal code from existing tests for a synchronous HTTP get, then hand it off to the handler. - Extend tests with Handler interpreting the same data. --- src/libcalamares/geoip/GeoIPTests.cpp | 7 ++- src/libcalamares/geoip/Handler.cpp | 61 ++++++++++++++++++++++++++- src/libcalamares/geoip/Handler.h | 29 +++++++++++++ 3 files changed, 94 insertions(+), 3 deletions(-) diff --git a/src/libcalamares/geoip/GeoIPTests.cpp b/src/libcalamares/geoip/GeoIPTests.cpp index f72388892..d4f40a251 100644 --- a/src/libcalamares/geoip/GeoIPTests.cpp +++ b/src/libcalamares/geoip/GeoIPTests.cpp @@ -22,6 +22,7 @@ #ifdef QT_XML_LIB #include "GeoIPXML.h" #endif +#include "Handler.h" #include #include @@ -219,14 +220,18 @@ synchronous_get( const char* urlstring ) #define CHECK_GET(t, selector, url) \ { \ auto tz = GeoIP##t( selector ).processReply( synchronous_get( url ) ); \ + qDebug() << tz; \ QCOMPARE( default_tz, tz ); \ + auto tz2 = CalamaresUtils::GeoIP::Handler( ""#t, url, selector ).query(); \ + qDebug() << tz2; \ + QCOMPARE( default_tz, tz2 ); \ } void GeoIPTests::testGet() { if ( !QProcessEnvironment::systemEnvironment().contains( QStringLiteral("TEST_HTTP_GET") ) ) { - qDebug() << "Skipping HTTP GET tests"; + qDebug() << "Skipping HTTP GET tests, set TEST_HTTP_GET environment variable to enable"; return; } diff --git a/src/libcalamares/geoip/Handler.cpp b/src/libcalamares/geoip/Handler.cpp index 22643d9ac..f5f8efd11 100644 --- a/src/libcalamares/geoip/Handler.cpp +++ b/src/libcalamares/geoip/Handler.cpp @@ -18,23 +18,80 @@ #include "Handler.h" +#include "GeoIPJSON.h" +#if defined(QT_XML_LIB) +#include "GeoIPXML.h" +#endif + +#include "utils/Logger.h" + +#include +#include +#include + namespace CalamaresUtils::GeoIP { Handler::Handler() + : m_interface( nullptr ) { } +Handler::Handler( const QString& implementation, const QString& url, const QString& selector ) + : m_interface( nullptr ) + , m_url( url ) +{ + if ( implementation.compare( "json", Qt::CaseInsensitive ) == 0 ) + { + m_interface = new GeoIPJSON( selector ); + } +#if defined(QT_XML_LIB) + else if ( implementation.compare( "xml", Qt::CaseInsensitive ) == 0 ) + { + m_interface = new GeoIPXML( selector ); + } +#endif + else + { + cWarning() << "GeoIP Style" << implementation << "is not recognized."; + } +} + +Handler::~Handler() +{ + delete m_interface; +} + bool Handler::isValid() const { - return false; + return m_interface; } +static QByteArray +synchronous_get( const QString& urlstring ) +{ + QUrl url( urlstring ); + QNetworkAccessManager manager; + QEventLoop loop; + + QObject::connect( &manager, &QNetworkAccessManager::finished, &loop, &QEventLoop::quit ); + + QNetworkRequest request( url ); + QNetworkReply* reply = manager.get( request ); + loop.exec(); + reply->deleteLater(); + return reply->readAll(); +} + + RegionZonePair Handler::query() const { - return RegionZonePair(); + if ( !isValid() ) + return RegionZonePair(); + + return m_interface->processReply( synchronous_get( m_url ) ); } } // namespace diff --git a/src/libcalamares/geoip/Handler.h b/src/libcalamares/geoip/Handler.h index 2e7bed888..e31e1d7df 100644 --- a/src/libcalamares/geoip/Handler.h +++ b/src/libcalamares/geoip/Handler.h @@ -21,6 +21,9 @@ #include "Interface.h" +#include +#include + namespace CalamaresUtils {} namespace CalamaresUtils::GeoIP { @@ -37,10 +40,36 @@ class DLLEXPORT Handler public: /** @brief An unconfigured handler; this always returns errors. */ Handler(); + /** @brief A handler for a specific GeoIP source. + * + * The @p implementation name selects an implementation; currently JSON and XML + * are supported. The @p url is retrieved by query() and then the @p selector + * is used to select something from the data returned by the @url. + */ + Handler( const QString& implementation, const QString& url, const QString& selector ); + /** @brief A handler for a specific GeoIP source. + * + * This is like the 3-QString Handler constructor, except the strings + * are extracted from the map, which is typically part of the configuration + * of a Calamares module. The strings are fetched from these keys: + * - implementation from "style" or "geoipStyle" (if the first does not exist) + * - url from "url" or "geoipUrl" (if the first does not exist) + * - selector from "selector" or "geoipSelector" (if the first does not exist) + * Unlike the 3-QString Handler constructor, this also understands implementations + * "legacy" and blank, which are interpreted as "JSON", except that the url is extended + * by "/json/" before fetching. + */ + Handler( const QVariantMap& config ); + + ~Handler(); RegionZonePair query() const; bool isValid() const; + +private: + Interface* m_interface; + const QString m_url; }; } // namespace From ee6e8de31a1f0e9686f325e7ad9d86214f0b8338 Mon Sep 17 00:00:00 2001 From: Adriaan de Groot Date: Thu, 2 May 2019 08:38:31 -0400 Subject: [PATCH 10/31] [libcalamares] Disable broken GeoIP providers - The tests were querying broken or disabled GeoIP providers, so remove them (this leaves only very few reliable free providers). --- src/libcalamares/geoip/GeoIPTests.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/libcalamares/geoip/GeoIPTests.cpp b/src/libcalamares/geoip/GeoIPTests.cpp index d4f40a251..a39a147b6 100644 --- a/src/libcalamares/geoip/GeoIPTests.cpp +++ b/src/libcalamares/geoip/GeoIPTests.cpp @@ -249,12 +249,9 @@ void GeoIPTests::testGet() // the TZ data is the same as the default_tz; this is fragile if the // services don't agree on the location of where the test is run. CHECK_GET( JSON, QString(), "https://geoip.kde.org/v1/calamares" ) // Check it's consistent - CHECK_GET( JSON, QString(), "http://freegeoip.net/json/" ) // Original FreeGeoIP service CHECK_GET( JSON, QStringLiteral("timezone"), "https://ipapi.co/json" ) // Different JSON CHECK_GET( JSON, QStringLiteral("timezone"), "http://ip-api.com/json" ) - CHECK_GET( JSON, QStringLiteral("location.time_zone"), "http://geoip.nekudo.com/api/" ) // 2-level JSON - CHECK_GET( JSON, QStringLiteral("Location.TimeZone"), "https://geoip.kde.org/debug" ) // 2-level JSON #ifdef QT_XML_LIB From 84a759a591c26d9165df45ebf6f4f8d75b636db1 Mon Sep 17 00:00:00 2001 From: Adriaan de Groot Date: Thu, 2 May 2019 11:01:01 -0400 Subject: [PATCH 11/31] [libcalamares] Emphasise that GeoIP::Handler::get() is synchronous - prep-work for also having an async API --- src/libcalamares/geoip/GeoIPTests.cpp | 2 +- src/libcalamares/geoip/Handler.cpp | 52 ++++++++++++++++++++------- src/libcalamares/geoip/Handler.h | 33 ++++++++++++++--- 3 files changed, 68 insertions(+), 19 deletions(-) diff --git a/src/libcalamares/geoip/GeoIPTests.cpp b/src/libcalamares/geoip/GeoIPTests.cpp index a39a147b6..ec7511370 100644 --- a/src/libcalamares/geoip/GeoIPTests.cpp +++ b/src/libcalamares/geoip/GeoIPTests.cpp @@ -222,7 +222,7 @@ synchronous_get( const char* urlstring ) auto tz = GeoIP##t( selector ).processReply( synchronous_get( url ) ); \ qDebug() << tz; \ QCOMPARE( default_tz, tz ); \ - auto tz2 = CalamaresUtils::GeoIP::Handler( ""#t, url, selector ).query(); \ + auto tz2 = CalamaresUtils::GeoIP::Handler( ""#t, url, selector ).get(); \ qDebug() << tz2; \ QCOMPARE( default_tz, tz2 ); \ } diff --git a/src/libcalamares/geoip/Handler.cpp b/src/libcalamares/geoip/Handler.cpp index f5f8efd11..98c8d194b 100644 --- a/src/libcalamares/geoip/Handler.cpp +++ b/src/libcalamares/geoip/Handler.cpp @@ -29,26 +29,29 @@ #include #include +#include + namespace CalamaresUtils::GeoIP { Handler::Handler() - : m_interface( nullptr ) + : m_type( Type::None ) { } Handler::Handler( const QString& implementation, const QString& url, const QString& selector ) - : m_interface( nullptr ) + : m_type( Type::None ) , m_url( url ) { if ( implementation.compare( "json", Qt::CaseInsensitive ) == 0 ) { - m_interface = new GeoIPJSON( selector ); + + m_type = Type::JSON; } #if defined(QT_XML_LIB) else if ( implementation.compare( "xml", Qt::CaseInsensitive ) == 0 ) { - m_interface = new GeoIPXML( selector ); + m_type = Type::XML; } #endif else @@ -59,13 +62,6 @@ Handler::Handler( const QString& implementation, const QString& url, const QStri Handler::~Handler() { - delete m_interface; -} - -bool -Handler::isValid() const -{ - return m_interface; } static QByteArray @@ -84,14 +80,44 @@ synchronous_get( const QString& urlstring ) return reply->readAll(); } +static std::unique_ptr< Interface > +create_interface( Handler::Type t, const QString& selector ) +{ + switch( t ) + { + case Handler::Type::None: + return nullptr; + case Handler::Type::JSON: + return std::make_unique< GeoIPJSON >( selector ); + case Handler::Type::XML: +#if defined(QT_XML_LIB) + return std::make_unique< GeoIPXML >( selector ); +#else + return nullptr; +#endif + default: // there are no others + return nullptr; + } +} RegionZonePair -Handler::query() const +Handler::get() const { if ( !isValid() ) return RegionZonePair(); - return m_interface->processReply( synchronous_get( m_url ) ); + const auto interface = create_interface( m_type, m_selector ); + if ( !interface ) + return RegionZonePair(); + + return interface->processReply( synchronous_get( m_url ) ); } +/* +QFuture< RegionZonePair > +Handler::query() const +{ +} +*/ + } // namespace diff --git a/src/libcalamares/geoip/Handler.h b/src/libcalamares/geoip/Handler.h index e31e1d7df..a07b62c7b 100644 --- a/src/libcalamares/geoip/Handler.h +++ b/src/libcalamares/geoip/Handler.h @@ -21,6 +21,7 @@ #include "Interface.h" +#include #include #include @@ -31,13 +32,21 @@ namespace CalamaresUtils::GeoIP /** @brief Handle one complete GeoIP lookup. * * This class handles one complete GeoIP lookup. Create it with - * suitable configuration values, then call lookup(). This is a + * suitable configuration values, then call get(). This is a * synchronous API and will return an invalid zone pair on - * error or if the configuration is not understood/ + * error or if the configuration is not understood. For an + * async API, use query(). */ class DLLEXPORT Handler { public: + enum class Type + { + None, + JSON, + XML + } ; + /** @brief An unconfigured handler; this always returns errors. */ Handler(); /** @brief A handler for a specific GeoIP source. @@ -63,13 +72,27 @@ public: ~Handler(); - RegionZonePair query() const; + /** @brief Synchronously get the GeoIP result. + * + * If the Handler is valid, then do the actual fetching and interpretation + * of data and return the result. An invalid Handler will return an + * invalid (empty) result. + */ + RegionZonePair get() const; - bool isValid() const; + /** @brief Asynchronously get the GeoIP result. + * + * See get() for the return value. + */ + QFuture< RegionZonePair > query() const; + + bool isValid() const { return m_type != Type::None; } + Type type() const { return m_type; } private: - Interface* m_interface; + Type m_type; const QString m_url; + const QString m_selector; }; } // namespace From 2f2adb3623d897358173b91c5eb6c21f299d8917 Mon Sep 17 00:00:00 2001 From: Adriaan de Groot Date: Thu, 2 May 2019 11:17:55 -0400 Subject: [PATCH 12/31] [libcalamares] Implement async GeoIP::Handler::query() - do this the cheap way by splitting the synchronous API into a free function and then calling that through QtConcurrent. --- src/libcalamares/geoip/Handler.cpp | 28 ++++++++++++++++++++-------- 1 file changed, 20 insertions(+), 8 deletions(-) diff --git a/src/libcalamares/geoip/Handler.cpp b/src/libcalamares/geoip/Handler.cpp index 98c8d194b..28cc2e3d6 100644 --- a/src/libcalamares/geoip/Handler.cpp +++ b/src/libcalamares/geoip/Handler.cpp @@ -100,24 +100,36 @@ create_interface( Handler::Type t, const QString& selector ) } } +static RegionZonePair +do_query( Handler::Type type, const QString& url, const QString& selector ) +{ + const auto interface = create_interface( type, selector ); + if ( !interface ) + return RegionZonePair(); + + return interface->processReply( synchronous_get( url ) ); +} + RegionZonePair Handler::get() const { if ( !isValid() ) return RegionZonePair(); - - const auto interface = create_interface( m_type, m_selector ); - if ( !interface ) - return RegionZonePair(); - - return interface->processReply( synchronous_get( m_url ) ); + return do_query( m_type, m_url, m_selector ); } -/* + QFuture< RegionZonePair > Handler::query() const { + Handler::Type type = m_type; + QString url = m_url; + QString selector = m_selector; + + return QtConcurrent::run( [=] + { + return do_query( type, url, selector ); + } ); } -*/ } // namespace From 25d97efe4896b918c344833acf358959a367eff8 Mon Sep 17 00:00:00 2001 From: Adriaan de Groot Date: Thu, 2 May 2019 13:48:19 -0400 Subject: [PATCH 13/31] [locale] Use GeoIP Handler instead of own implementation --- src/modules/locale/LocaleViewStep.cpp | 90 ++++++--------------------- src/modules/locale/LocaleViewStep.h | 12 ++-- 2 files changed, 26 insertions(+), 76 deletions(-) diff --git a/src/modules/locale/LocaleViewStep.cpp b/src/modules/locale/LocaleViewStep.cpp index 6ad73cfbe..9557fa3a7 100644 --- a/src/modules/locale/LocaleViewStep.cpp +++ b/src/modules/locale/LocaleViewStep.cpp @@ -26,11 +26,7 @@ #include "GlobalStorage.h" #include "JobQueue.h" -#include "geoip/Interface.h" -#include "geoip/GeoIPJSON.h" -#ifdef QT_XML_LIB -#include "geoip/GeoIPXML.h" -#endif +#include "geoip/Handler.h" #include "utils/CalamaresUtilsGui.h" #include "utils/Logger.h" @@ -117,56 +113,16 @@ LocaleViewStep::setUpPage() void LocaleViewStep::fetchGeoIpTimezone() { - using namespace CalamaresUtils::GeoIP; - - QString actualUrl( m_geoipUrl ); - Interface* handler = nullptr; - - if ( m_geoipStyle.isEmpty() || m_geoipStyle == "legacy" ) + CalamaresUtils::GeoIP::Handler h( m_geoipStyle, m_geoipUrl, m_geoipSelector ); + if ( h.isValid() ) { - actualUrl.append( "/json/" ); - handler = new GeoIPJSON( m_geoipSelector ); + m_startingTimezone = h.get(); + if ( !m_startingTimezone.isValid() ) + cWarning() << "GeoIP lookup at" << m_geoipUrl << "failed."; } - else if ( m_geoipStyle == "json" ) - { - handler = new GeoIPJSON( m_geoipSelector ); - } -#if defined(QT_XML_LIB) - else if ( m_geoipStyle == "xml" ) - { - handler = new GeoIPXML( m_geoipSelector ); - } -#endif else - { cWarning() << "GeoIP Style" << m_geoipStyle << "is not recognized."; - setUpPage(); - return; - } - cDebug() << "Fetching GeoIP data from" << actualUrl; - - QNetworkAccessManager *manager = new QNetworkAccessManager( this ); - connect( manager, &QNetworkAccessManager::finished, - [=]( QNetworkReply* reply ) - { - if ( reply->error() == QNetworkReply::NoError ) - { - auto tz = handler->processReply( reply->readAll() ); - if ( !tz.first.isEmpty() ) - m_startingTimezone = tz; - else - cWarning() << "GeoIP lookup at" << reply->url() << "failed."; - } - delete handler; - reply->deleteLater(); - manager->deleteLater(); - setUpPage(); - } ); - - QNetworkRequest request; - request.setUrl( QUrl::fromUserInput( actualUrl ) ); - request.setAttribute( QNetworkRequest::FollowRedirectsAttribute, true ); - manager->get( request ); + setUpPage(); } @@ -254,35 +210,29 @@ LocaleViewStep::onLeave() void LocaleViewStep::setConfigurationMap( const QVariantMap& configurationMap ) { - if ( configurationMap.contains( "region" ) && - configurationMap.value( "region" ).type() == QVariant::String && - !configurationMap.value( "region" ).toString().isEmpty() && - configurationMap.contains( "zone" ) && - configurationMap.value( "zone" ).type() == QVariant::String && - !configurationMap.value( "zone" ).toString().isEmpty() ) + QString region = CalamaresUtils::getString( configurationMap, "region" ); + QString zone = CalamaresUtils::getString( configurationMap, "zone" ); + if ( !region.isEmpty() && !zone.isEmpty() ) { - m_startingTimezone = qMakePair( configurationMap.value( "region" ).toString(), - configurationMap.value( "zone" ).toString() ); + m_startingTimezone = CalamaresUtils::GeoIP::RegionZonePair( region, zone ); } else { - m_startingTimezone = qMakePair( QStringLiteral( "America" ), - QStringLiteral( "New_York" ) ); + m_startingTimezone = CalamaresUtils::GeoIP::RegionZonePair( QStringLiteral( "America" ), QStringLiteral( "New_York" ) ); } - if ( configurationMap.contains( "localeGenPath" ) && - configurationMap.value( "localeGenPath" ).type() == QVariant::String && - !configurationMap.value( "localeGenPath" ).toString().isEmpty() ) - { - m_localeGenPath = configurationMap.value( "localeGenPath" ).toString(); - } - else - { + m_localeGenPath = CalamaresUtils::getString( configurationMap, "localeGenPath" ); + if ( m_localeGenPath.isEmpty() ) m_localeGenPath = QStringLiteral( "/etc/locale.gen" ); - } // Optional m_geoipUrl = CalamaresUtils::getString( configurationMap, "geoipUrl" ); m_geoipStyle = CalamaresUtils::getString( configurationMap, "geoipStyle" ); m_geoipSelector = CalamaresUtils::getString( configurationMap, "geoipSelector" ); + + if ( !m_geoipUrl.isEmpty() && ( m_geoipStyle.isEmpty() || m_geoipStyle == "legacy" ) ) + { + m_geoipStyle = "json"; + m_geoipUrl.append( "/json/" ); + } } diff --git a/src/modules/locale/LocaleViewStep.h b/src/modules/locale/LocaleViewStep.h index 3f5c91621..8ab50b75d 100644 --- a/src/modules/locale/LocaleViewStep.h +++ b/src/modules/locale/LocaleViewStep.h @@ -20,14 +20,14 @@ #ifndef LOCALEVIEWSTEP_H #define LOCALEVIEWSTEP_H -#include +#include "geoip/Interface.h" +#include "utils/PluginFactory.h" +#include "viewpages/ViewStep.h" -#include -#include - -#include +#include "PluginDllMacro.h" #include +#include class LocalePage; class WaitingWidget; @@ -71,7 +71,7 @@ private: bool m_nextEnabled; QString m_prettyStatus; - QPair< QString, QString > m_startingTimezone; + CalamaresUtils::GeoIP::RegionZonePair m_startingTimezone; QString m_localeGenPath; QString m_geoipUrl; // The URL, depening on style might be modified on lookup From f1ddd0c233c61a1f649de443a2ee6ad6a9e16673 Mon Sep 17 00:00:00 2001 From: Adriaan de Groot Date: Thu, 2 May 2019 14:00:32 -0400 Subject: [PATCH 14/31] [welcome] Simplify configuration code --- src/modules/welcome/WelcomeViewStep.cpp | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/src/modules/welcome/WelcomeViewStep.cpp b/src/modules/welcome/WelcomeViewStep.cpp index 88b5f6324..d1c2cc840 100644 --- a/src/modules/welcome/WelcomeViewStep.cpp +++ b/src/modules/welcome/WelcomeViewStep.cpp @@ -24,6 +24,7 @@ #include "modulesystem/ModuleManager.h" #include "utils/Logger.h" +#include "utils/Variant.h" #include @@ -97,18 +98,9 @@ WelcomeViewStep::jobs() const void WelcomeViewStep::setConfigurationMap( const QVariantMap& configurationMap ) { - bool showSupportUrl = - configurationMap.contains( "showSupportUrl" ) && - configurationMap.value( "showSupportUrl" ).type() == QVariant::Bool && - configurationMap.value( "showSupportUrl" ).toBool(); - bool showKnownIssuesUrl = - configurationMap.contains( "showKnownIssuesUrl" ) && - configurationMap.value( "showKnownIssuesUrl" ).type() == QVariant::Bool && - configurationMap.value( "showKnownIssuesUrl" ).toBool(); - bool showReleaseNotesUrl = - configurationMap.contains( "showReleaseNotesUrl" ) && - configurationMap.value( "showReleaseNotesUrl" ).type() == QVariant::Bool && - configurationMap.value( "showReleaseNotesUrl" ).toBool(); + bool showSupportUrl = CalamaresUtils::getBool( configurationMap, "showSupportUrl", false ); + bool showKnownIssuesUrl = CalamaresUtils::getBool( configurationMap, "showKnownIssuesUrl", false ); + bool showReleaseNotesUrl = CalamaresUtils::getBool( configurationMap, "showReleaseNotesUrl", false ); m_widget->setUpLinks( showSupportUrl, showKnownIssuesUrl, From d5fe86c3941f9aa7a560759061a664b617551927 Mon Sep 17 00:00:00 2001 From: Adriaan de Groot Date: Fri, 3 May 2019 11:00:57 -0400 Subject: [PATCH 15/31] [libcalamares] Use NamedEnum for named-enum wrangling --- src/libcalamares/geoip/Handler.cpp | 31 +++++++++++++++++++++--------- 1 file changed, 22 insertions(+), 9 deletions(-) diff --git a/src/libcalamares/geoip/Handler.cpp b/src/libcalamares/geoip/Handler.cpp index 28cc2e3d6..ce500489b 100644 --- a/src/libcalamares/geoip/Handler.cpp +++ b/src/libcalamares/geoip/Handler.cpp @@ -24,6 +24,7 @@ #endif #include "utils/Logger.h" +#include "utils/NamedEnum.h" #include #include @@ -31,6 +32,20 @@ #include +static const NamedEnumTable< CalamaresUtils::GeoIP::Handler::Type >& +handlerTypes() +{ + using Type = CalamaresUtils::GeoIP::Handler::Type; + + static const NamedEnumTable names{ + { QStringLiteral( "none" ), Type::None}, + { QStringLiteral( "json" ), Type::JSON}, + { QStringLiteral( "xml" ), Type::XML} + }; + + return names; +} + namespace CalamaresUtils::GeoIP { @@ -43,18 +58,16 @@ Handler::Handler( const QString& implementation, const QString& url, const QStri : m_type( Type::None ) , m_url( url ) { - if ( implementation.compare( "json", Qt::CaseInsensitive ) == 0 ) + bool ok = false; + m_type = handlerTypes().find( implementation, ok ); +#if !defined(QT_XML_LIB) + if ( m_type == Type::XML ) { - - m_type = Type::JSON; - } -#if defined(QT_XML_LIB) - else if ( implementation.compare( "xml", Qt::CaseInsensitive ) == 0 ) - { - m_type = Type::XML; + m_type = Type::None; + cWarning() << "GeoIP style XML is not supported in this version of Calamares."; } #endif - else + if ( !ok ) { cWarning() << "GeoIP Style" << implementation << "is not recognized."; } From fc76313ea6c57b2f684ce4c96a7758f025dc2792 Mon Sep 17 00:00:00 2001 From: Adriaan de Groot Date: Fri, 3 May 2019 11:06:36 -0400 Subject: [PATCH 16/31] [libcalamares] Implement GeoIP Handler config from map - read map entries with alternate keys - delegate to other constructor --- src/libcalamares/geoip/Handler.cpp | 17 +++++++++++++++++ src/libcalamares/geoip/Handler.h | 3 --- 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/src/libcalamares/geoip/Handler.cpp b/src/libcalamares/geoip/Handler.cpp index ce500489b..3ee41eaa5 100644 --- a/src/libcalamares/geoip/Handler.cpp +++ b/src/libcalamares/geoip/Handler.cpp @@ -25,6 +25,7 @@ #include "utils/Logger.h" #include "utils/NamedEnum.h" +#include "utils/Variant.h" #include #include @@ -73,6 +74,22 @@ Handler::Handler( const QString& implementation, const QString& url, const QStri } } +static QString +getMapAlternates( const QVariantMap& config, const QString& key1, const QString& key2 ) +{ + QString r = CalamaresUtils::getString( config, key1 ); + if ( r.isEmpty() ) + r = CalamaresUtils::getString( config, key2 ); + return r; +} + +Handler::Handler( const QVariantMap& config ) + : Handler( getMapAlternates( config, QStringLiteral( "style" ), QStringLiteral( "geoipStyle" ) ), + getMapAlternates( config, QStringLiteral( "url" ), QStringLiteral( "geoipUrl" ) ), + getMapAlternates( config, QStringLiteral( "selector" ), QStringLiteral( "geoipSelector" ) ) ) +{ +} + Handler::~Handler() { } diff --git a/src/libcalamares/geoip/Handler.h b/src/libcalamares/geoip/Handler.h index a07b62c7b..8285682dd 100644 --- a/src/libcalamares/geoip/Handler.h +++ b/src/libcalamares/geoip/Handler.h @@ -64,9 +64,6 @@ public: * - implementation from "style" or "geoipStyle" (if the first does not exist) * - url from "url" or "geoipUrl" (if the first does not exist) * - selector from "selector" or "geoipSelector" (if the first does not exist) - * Unlike the 3-QString Handler constructor, this also understands implementations - * "legacy" and blank, which are interpreted as "JSON", except that the url is extended - * by "/json/" before fetching. */ Handler( const QVariantMap& config ); From 44cbb0d3744a833aa7525e4a5105bd72398fab91 Mon Sep 17 00:00:00 2001 From: Adriaan de Groot Date: Fri, 3 May 2019 11:21:01 -0400 Subject: [PATCH 17/31] [libcalamares] Drop alternate-config handling for GeoIP - Dealing with legacy formats and alternate configurations is something that consumers should do (and then hand off to the 3-string constructor) instead. --- src/libcalamares/geoip/Handler.cpp | 15 +++------------ src/libcalamares/geoip/Handler.h | 6 +++--- 2 files changed, 6 insertions(+), 15 deletions(-) diff --git a/src/libcalamares/geoip/Handler.cpp b/src/libcalamares/geoip/Handler.cpp index 3ee41eaa5..a803889b2 100644 --- a/src/libcalamares/geoip/Handler.cpp +++ b/src/libcalamares/geoip/Handler.cpp @@ -74,19 +74,10 @@ Handler::Handler( const QString& implementation, const QString& url, const QStri } } -static QString -getMapAlternates( const QVariantMap& config, const QString& key1, const QString& key2 ) -{ - QString r = CalamaresUtils::getString( config, key1 ); - if ( r.isEmpty() ) - r = CalamaresUtils::getString( config, key2 ); - return r; -} - Handler::Handler( const QVariantMap& config ) - : Handler( getMapAlternates( config, QStringLiteral( "style" ), QStringLiteral( "geoipStyle" ) ), - getMapAlternates( config, QStringLiteral( "url" ), QStringLiteral( "geoipUrl" ) ), - getMapAlternates( config, QStringLiteral( "selector" ), QStringLiteral( "geoipSelector" ) ) ) + : Handler( CalamaresUtils::getString( config, QStringLiteral( "style" ) ), + CalamaresUtils::getString( config, QStringLiteral( "url" ) ), + CalamaresUtils::getString( config, QStringLiteral( "selector" ) ) ) { } diff --git a/src/libcalamares/geoip/Handler.h b/src/libcalamares/geoip/Handler.h index 8285682dd..0a5ec1e12 100644 --- a/src/libcalamares/geoip/Handler.h +++ b/src/libcalamares/geoip/Handler.h @@ -61,9 +61,9 @@ public: * This is like the 3-QString Handler constructor, except the strings * are extracted from the map, which is typically part of the configuration * of a Calamares module. The strings are fetched from these keys: - * - implementation from "style" or "geoipStyle" (if the first does not exist) - * - url from "url" or "geoipUrl" (if the first does not exist) - * - selector from "selector" or "geoipSelector" (if the first does not exist) + * - implementation from "style" + * - url from "url" + * - selector from "selector" */ Handler( const QVariantMap& config ); From 7899ab83f91d377ded8a1d52676029228e9a07f5 Mon Sep 17 00:00:00 2001 From: Adriaan de Groot Date: Fri, 3 May 2019 11:35:13 -0400 Subject: [PATCH 18/31] [libcalamares] Remove convenience API --- src/libcalamares/geoip/Handler.cpp | 7 ------- src/libcalamares/geoip/Handler.h | 10 ---------- 2 files changed, 17 deletions(-) diff --git a/src/libcalamares/geoip/Handler.cpp b/src/libcalamares/geoip/Handler.cpp index a803889b2..f98ac897d 100644 --- a/src/libcalamares/geoip/Handler.cpp +++ b/src/libcalamares/geoip/Handler.cpp @@ -74,13 +74,6 @@ Handler::Handler( const QString& implementation, const QString& url, const QStri } } -Handler::Handler( const QVariantMap& config ) - : Handler( CalamaresUtils::getString( config, QStringLiteral( "style" ) ), - CalamaresUtils::getString( config, QStringLiteral( "url" ) ), - CalamaresUtils::getString( config, QStringLiteral( "selector" ) ) ) -{ -} - Handler::~Handler() { } diff --git a/src/libcalamares/geoip/Handler.h b/src/libcalamares/geoip/Handler.h index 0a5ec1e12..533188a0d 100644 --- a/src/libcalamares/geoip/Handler.h +++ b/src/libcalamares/geoip/Handler.h @@ -56,16 +56,6 @@ public: * is used to select something from the data returned by the @url. */ Handler( const QString& implementation, const QString& url, const QString& selector ); - /** @brief A handler for a specific GeoIP source. - * - * This is like the 3-QString Handler constructor, except the strings - * are extracted from the map, which is typically part of the configuration - * of a Calamares module. The strings are fetched from these keys: - * - implementation from "style" - * - url from "url" - * - selector from "selector" - */ - Handler( const QVariantMap& config ); ~Handler(); From 8774b605faa48eb8cff2b2a60e522eee1c5765c9 Mon Sep 17 00:00:00 2001 From: Adriaan de Groot Date: Fri, 3 May 2019 11:37:12 -0400 Subject: [PATCH 19/31] [locale] Update to use newer configuration - deprecate the old entries - use a geoip sub-map for GeoIP configuration - polish up documentation - drop mention of blank and "legacy" styles for GeoIP config, just update your URLs already. --- CHANGES | 5 ++ src/modules/locale/LocaleViewStep.cpp | 30 +++++++--- src/modules/locale/locale.conf | 82 +++++++++++++-------------- 3 files changed, 65 insertions(+), 52 deletions(-) diff --git a/CHANGES b/CHANGES index db141384d..87ba91d6c 100644 --- a/CHANGES +++ b/CHANGES @@ -24,6 +24,11 @@ This release contains contributions from (alphabetically by first name): ## Modules ## + - *locale* module GeoIP configuration has a new preferred format. + See `locale.conf` for details. The old configuration is still + supported but will be phased out before 3.3.0 -- in particular, + support for "legacy" format will be removed, since that was a + crutch for the disappearance of one GeoIP provider in 2018. - *oemid* is a new module for configuring OEM phase-0 (image pre-mastering, or pre-deployment) things. It has limited functionality at the moment, writing only a single batch-identifier file. diff --git a/src/modules/locale/LocaleViewStep.cpp b/src/modules/locale/LocaleViewStep.cpp index 9557fa3a7..29006ec33 100644 --- a/src/modules/locale/LocaleViewStep.cpp +++ b/src/modules/locale/LocaleViewStep.cpp @@ -225,14 +225,28 @@ LocaleViewStep::setConfigurationMap( const QVariantMap& configurationMap ) if ( m_localeGenPath.isEmpty() ) m_localeGenPath = QStringLiteral( "/etc/locale.gen" ); - // Optional - m_geoipUrl = CalamaresUtils::getString( configurationMap, "geoipUrl" ); - m_geoipStyle = CalamaresUtils::getString( configurationMap, "geoipStyle" ); - m_geoipSelector = CalamaresUtils::getString( configurationMap, "geoipSelector" ); - - if ( !m_geoipUrl.isEmpty() && ( m_geoipStyle.isEmpty() || m_geoipStyle == "legacy" ) ) + bool ok = false; + QVariantMap geoip = CalamaresUtils::getSubMap( configurationMap, "geoip", ok ); + if ( ok ) { - m_geoipStyle = "json"; - m_geoipUrl.append( "/json/" ); + m_geoipUrl = CalamaresUtils::getString( geoip, "url" ); + m_geoipStyle = CalamaresUtils::getString( geoip, "style" ); + m_geoipSelector = CalamaresUtils::getString( geoip, "selector" ); + } + else + { + // Optional + m_geoipUrl = CalamaresUtils::getString( configurationMap, "geoipUrl" ); + m_geoipStyle = CalamaresUtils::getString( configurationMap, "geoipStyle" ); + m_geoipSelector = CalamaresUtils::getString( configurationMap, "geoipSelector" ); + + if ( !m_geoipUrl.isEmpty() && ( m_geoipStyle.isEmpty() || m_geoipStyle == "legacy" ) ) + { + m_geoipStyle = "json"; + m_geoipUrl.append( "/json/" ); + } + + if ( !m_geoipUrl.isEmpty() ) + cWarning() << "Legacy-style GeoIP configuration is deprecated. Use geoip: map."; } } diff --git a/src/modules/locale/locale.conf b/src/modules/locale/locale.conf index ddd0bc97e..7c2ec332c 100644 --- a/src/modules/locale/locale.conf +++ b/src/modules/locale/locale.conf @@ -25,21 +25,46 @@ zone: "New_York" # custom path for locale.gen #localeGenPath: "PATH_TO/locale.gen" -# GeoIP based Language settings: +# GeoIP based Language settings: Leave commented out to disable GeoIP. # -# GeoIP need an working Internet connection. +# GeoIP needs a working Internet connection. # This can be managed from `welcome.conf` by adding # internet to the list of required conditions. # -# Leave commented out to disable GeoIP. +# The configuration +# is in three parts: a *style*, which can be "json" or "xml" +# depending on the kind of data returned by the service, and +# a *url* where the data is retrieved, and an optional *selector* +# to pick the right field out of the returned data (e.g. field +# name in JSON or element name in XML). # -# An HTTP request is made to *geoipUrl* -- depending on the geoipStyle, -# the URL may be modified before use. The request should return -# valid data in a suitable format, depending on geoipStyle; +# The default selector (when the setting is blank) is picked to +# work with existing JSON providers (which use "time_zone") and +# Ubiquity's XML providers (which use "TimeZone"). +# +# If the service configured via *url* uses +# a different attribute name (e.g. "timezone") in JSON or a +# different element tag (e.g. "") in XML, set this +# string to the name or tag to be used. +# +# In JSON: +# - if the string contains "." characters, this is used as a +# multi-level selector, e.g. "a.b" will select the timezone +# from data "{a: {b: "Europe/Amsterdam" } }". +# - each part of the string split by "." characters is used as +# a key into the JSON data. +# In XML: +# - all elements with the named tag (e.g. all TimeZone) elements +# from the document are checked; the first one with non-empty +# text value is used. +# +# +# An HTTP(S) request is made to *url*. The request should return +# valid data in a suitable format, depending on *style*; # generally this includes a string value with the timezone # in / format. For services that return data which # does not follow the conventions of "suitable data" described -# below, *geoIPSelector* may be used to pick different data. +# below, *selector* may be used to pick different data. # # Note that this example URL works, but the service is shutting # down in June 2018. @@ -58,40 +83,9 @@ zone: "New_York" # - backslashes are removed # - spaces are replaced with _ # -#geoipUrl: "freegeoip.net" - -# GeoIP style. Leave commented out for the "legacy" interpretation. -# This setting only makes sense if geoipUrl is set, enabliing geoIP. -# -# Possible values are: -# unset same as "legacy" -# blank same as "legacy" -# "legacy" appends "/json" to geoipUrl, above, and uses JSON format -# (which is what freegeoip.net provides there). -# "json" URL is not modified, uses JSON format. -# "xml" URL is not modified, uses XML format. -# -# The JSON format is provided by freegeoip.net, but that service is -# shutting down in June 2018. There are other providers with the same -# format. XML format is provided for Ubiquity. -#geoipStyle: "legacy" - -# GeoIP selector. Leave commented out for the default selector -# (which depends on the style: JSON uses "time_zone" and XML -# uses TimeZone, for the FreeGeoIP-alike and the Ubiquity-alike -# respectively). If the service configured via *geoipUrl* uses -# a different attribute name (e.g. "timezone") in JSON or a -# different element tag (e.g. "") in XML, set this -# string to the name or tag to be used. -# -# In JSON: -# - if the string contains "." characters, this is used as a -# multi-level selector, e.g. "a.b" will select the timezone -# from data "{a: {b: "Europe/Amsterdam" } }". -# - each part of the string split by "." characters is used as -# a key into the JSON data. -# In XML: -# - all elements with the named tag (e.g. all TimeZone) elements -# from the document are checked; the first one with non-empty -# text value is used. -#geoipSelector: "" +# Legacy settings "geoipStyle", "geoipUrl" and "geoipSelector" +# in the top-level are still supported, but I'd advise against. +geoip: + style: "json" + url: "https://geoip.kde.org/v1/calamares" + selector: "" # leave blank for the default From 9931b2df4448d17673c356c87b100ec6bdb19da8 Mon Sep 17 00:00:00 2001 From: Adriaan de Groot Date: Thu, 9 May 2019 10:15:53 -0400 Subject: [PATCH 20/31] [libcalamares] Add "raw" support for extracting data from GeoIP - This is prep-work for getting something other than the timezone (e.g. most extended formats also support Country). --- src/libcalamares/geoip/GeoIPJSON.cpp | 22 ++++++++++--- src/libcalamares/geoip/GeoIPJSON.h | 3 +- src/libcalamares/geoip/GeoIPXML.cpp | 47 +++++++++++++++++++++------- src/libcalamares/geoip/GeoIPXML.h | 3 +- src/libcalamares/geoip/Handler.h | 6 ++++ src/libcalamares/geoip/Interface.h | 3 ++ 6 files changed, 67 insertions(+), 17 deletions(-) diff --git a/src/libcalamares/geoip/GeoIPJSON.cpp b/src/libcalamares/geoip/GeoIPJSON.cpp index 801031c9e..61b9fd8d6 100644 --- a/src/libcalamares/geoip/GeoIPJSON.cpp +++ b/src/libcalamares/geoip/GeoIPJSON.cpp @@ -33,6 +33,12 @@ GeoIPJSON::GeoIPJSON(const QString& attribute) { } +/** @brief Indexes into a map @m by selectors @p l + * + * Each element of @p l is an index into map @m or a sub-map thereof, + * so that "foo.bar.baz" looks up "baz" in the sub-map "bar" of sub-map + * "foo" of @p m, like a regular JSON lookup would. + */ static QString selectMap( const QVariantMap& m, const QStringList& l, int index) { @@ -51,8 +57,8 @@ selectMap( const QVariantMap& m, const QStringList& l, int index) } } -GeoIP::RegionZonePair -GeoIPJSON::processReply( const QByteArray& data ) +QString +GeoIPJSON::rawReply( const QByteArray& data ) { try { @@ -63,7 +69,7 @@ GeoIPJSON::processReply( const QByteArray& data ) var.isValid() && var.type() == QVariant::Map ) { - return splitTZString( selectMap( var.toMap(), m_element.split('.'), 0 ) ); + return selectMap( var.toMap(), m_element.split('.'), 0 ); } else cWarning() << "Invalid YAML data for GeoIPJSON"; @@ -73,7 +79,15 @@ GeoIPJSON::processReply( const QByteArray& data ) CalamaresUtils::explainYamlException( e, data, "GeoIP data"); } - return RegionZonePair( QString(), QString() ); + return QString(); } +GeoIP::RegionZonePair +GeoIPJSON::processReply( const QByteArray& data ) +{ + return splitTZString( rawReply( data ) ); +} + + + } // namespace diff --git a/src/libcalamares/geoip/GeoIPJSON.h b/src/libcalamares/geoip/GeoIPJSON.h index 355fa0739..584825d70 100644 --- a/src/libcalamares/geoip/GeoIPJSON.h +++ b/src/libcalamares/geoip/GeoIPJSON.h @@ -42,7 +42,8 @@ public: */ explicit GeoIPJSON( const QString& attribute = QString() ); - virtual RegionZonePair processReply( const QByteArray& ); + virtual RegionZonePair processReply( const QByteArray& ) override; + virtual QString rawReply(const QByteArray & ) override; } ; } // namespace diff --git a/src/libcalamares/geoip/GeoIPXML.cpp b/src/libcalamares/geoip/GeoIPXML.cpp index e67354e1d..a4b9bb146 100644 --- a/src/libcalamares/geoip/GeoIPXML.cpp +++ b/src/libcalamares/geoip/GeoIPXML.cpp @@ -31,35 +31,60 @@ GeoIPXML::GeoIPXML( const QString& element ) { } -GeoIP::RegionZonePair -GeoIPXML::processReply( const QByteArray& data ) +static QStringList +getElementTexts( const QByteArray& data, const QString& tag ) { + QStringList elements; + QString domError; int errorLine, errorColumn; QDomDocument doc; if ( doc.setContent( data, false, &domError, &errorLine, &errorColumn ) ) { - const auto tzElements = doc.elementsByTagName( m_element ); + const auto tzElements = doc.elementsByTagName( tag ); cDebug() << "GeoIP found" << tzElements.length() << "elements"; for ( int it = 0; it < tzElements.length(); ++it ) { auto e = tzElements.at(it).toElement(); - auto tz = splitTZString( e.text() ); - if ( !tz.first.isEmpty() ) - return tz; + auto e_text = e.text(); + if ( !e_text.isEmpty() ) + elements.append( e_text ); } - - // None of them valid - cWarning() << "GeopIP XML had no recognizable timezone"; - return RegionZonePair( QString(), QString() ); } else { cWarning() << "GeoIP XML data error:" << domError << "(line" << errorLine << errorColumn << ')'; } - return RegionZonePair( QString(), QString() ); + if ( elements.count() < 1 ) + cWarning() << "GeopIP XML had no non-empty elements" << tag; + + return elements; +} + + +QString +GeoIPXML::rawReply( const QByteArray& data ) +{ + for ( const auto& e : getElementTexts( data, m_element ) ) + if ( !e.isEmpty() ) + return e; + + return QString(); +} + +GeoIP::RegionZonePair +GeoIPXML::processReply( const QByteArray& data ) +{ + for ( const auto& e : getElementTexts( data, m_element ) ) + { + auto tz = splitTZString( e ); + if ( !tz.first.isEmpty() ) + return tz; + } + + return RegionZonePair(); } } // namespace diff --git a/src/libcalamares/geoip/GeoIPXML.h b/src/libcalamares/geoip/GeoIPXML.h index 367c307f8..7dee2ecbe 100644 --- a/src/libcalamares/geoip/GeoIPXML.h +++ b/src/libcalamares/geoip/GeoIPXML.h @@ -42,7 +42,8 @@ public: */ explicit GeoIPXML( const QString& element = QString() ); - virtual RegionZonePair processReply( const QByteArray& ); + virtual RegionZonePair processReply( const QByteArray& ) override; + virtual QString rawReply(const QByteArray & ) override; } ; } // namespace diff --git a/src/libcalamares/geoip/Handler.h b/src/libcalamares/geoip/Handler.h index 533188a0d..b095c59ac 100644 --- a/src/libcalamares/geoip/Handler.h +++ b/src/libcalamares/geoip/Handler.h @@ -66,12 +66,18 @@ public: * invalid (empty) result. */ RegionZonePair get() const; + /// @brief Like get, but don't interpret the contents + QString getRaw() const; /** @brief Asynchronously get the GeoIP result. * * See get() for the return value. */ QFuture< RegionZonePair > query() const; + /// @brief Like query, but don't interpret the contents + QFuture< QString > queryRaw() const; + + bool isValid() const { return m_type != Type::None; } Type type() const { return m_type; } diff --git a/src/libcalamares/geoip/Interface.h b/src/libcalamares/geoip/Interface.h index 94c6b3c20..4b2ff3a5a 100644 --- a/src/libcalamares/geoip/Interface.h +++ b/src/libcalamares/geoip/Interface.h @@ -85,6 +85,9 @@ public: */ virtual RegionZonePair processReply( const QByteArray& ) = 0; + /** @brief Get the raw reply data. */ + virtual QString rawReply( const QByteArray& ) = 0; + protected: Interface( const QString& e = QString() ); From 4ea29b1cf1c8a583126a71b0db2a60a2efb75897 Mon Sep 17 00:00:00 2001 From: Adriaan de Groot Date: Thu, 9 May 2019 10:40:51 -0400 Subject: [PATCH 21/31] [libcalamares] Implement "raw" handling --- src/libcalamares/geoip/Handler.cpp | 33 ++++++++++++++++++++++++++++++ src/libcalamares/geoip/Handler.h | 2 -- 2 files changed, 33 insertions(+), 2 deletions(-) diff --git a/src/libcalamares/geoip/Handler.cpp b/src/libcalamares/geoip/Handler.cpp index f98ac897d..7aa8ee701 100644 --- a/src/libcalamares/geoip/Handler.cpp +++ b/src/libcalamares/geoip/Handler.cpp @@ -124,6 +124,16 @@ do_query( Handler::Type type, const QString& url, const QString& selector ) return interface->processReply( synchronous_get( url ) ); } +static QString +do_raw_query( Handler::Type type, const QString& url, const QString& selector ) +{ + const auto interface = create_interface( type, selector ); + if ( !interface ) + return QString(); + + return interface->rawReply( synchronous_get( url ) ); +} + RegionZonePair Handler::get() const { @@ -146,4 +156,27 @@ Handler::query() const } ); } +QString +Handler::getRaw() const +{ + if ( !isValid() ) + return QString(); + return do_raw_query( m_type, m_url, m_selector ); +} + + +QFuture< QString > +Handler::queryRaw() const +{ + Handler::Type type = m_type; + QString url = m_url; + QString selector = m_selector; + + return QtConcurrent::run( [=] + { + return do_raw_query( type, url, selector ); + } ); +} + + } // namespace diff --git a/src/libcalamares/geoip/Handler.h b/src/libcalamares/geoip/Handler.h index b095c59ac..92e5f326e 100644 --- a/src/libcalamares/geoip/Handler.h +++ b/src/libcalamares/geoip/Handler.h @@ -77,8 +77,6 @@ public: /// @brief Like query, but don't interpret the contents QFuture< QString > queryRaw() const; - - bool isValid() const { return m_type != Type::None; } Type type() const { return m_type; } From 44559d24bdfeb4391332f3d8814f172f777d2b72 Mon Sep 17 00:00:00 2001 From: Adriaan de Groot Date: Thu, 9 May 2019 15:09:58 -0400 Subject: [PATCH 22/31] [libcalamares] Selector wasn't saved for later queries --- src/libcalamares/geoip/Handler.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/libcalamares/geoip/Handler.cpp b/src/libcalamares/geoip/Handler.cpp index 7aa8ee701..1e8b03b26 100644 --- a/src/libcalamares/geoip/Handler.cpp +++ b/src/libcalamares/geoip/Handler.cpp @@ -58,6 +58,7 @@ Handler::Handler() Handler::Handler( const QString& implementation, const QString& url, const QString& selector ) : m_type( Type::None ) , m_url( url ) + , m_selector( selector ) { bool ok = false; m_type = handlerTypes().find( implementation, ok ); From cb7c38dabac4dba625a081cfa7d21cec66694df5 Mon Sep 17 00:00:00 2001 From: Adriaan de Groot Date: Thu, 9 May 2019 15:15:03 -0400 Subject: [PATCH 23/31] [welcome] Support GeoIP country lookup --- src/modules/welcome/WelcomeViewStep.cpp | 22 ++++++++++++++++++++++ src/modules/welcome/welcome.conf | 13 +++++++++++++ 2 files changed, 35 insertions(+) diff --git a/src/modules/welcome/WelcomeViewStep.cpp b/src/modules/welcome/WelcomeViewStep.cpp index d1c2cc840..91745967e 100644 --- a/src/modules/welcome/WelcomeViewStep.cpp +++ b/src/modules/welcome/WelcomeViewStep.cpp @@ -22,10 +22,12 @@ #include "WelcomePage.h" #include "checker/GeneralRequirements.h" +#include "geoip/Handler.h" #include "modulesystem/ModuleManager.h" #include "utils/Logger.h" #include "utils/Variant.h" +#include #include CALAMARES_PLUGIN_FACTORY_DEFINITION( WelcomeViewStepFactory, registerPlugin(); ) @@ -112,6 +114,26 @@ WelcomeViewStep::setConfigurationMap( const QVariantMap& configurationMap ) else cWarning() << "no valid requirements map found in welcome " "module configuration."; + + bool ok = false; + QVariantMap geoip = CalamaresUtils::getSubMap( configurationMap, "geoip", ok ); + if ( ok ) + { + using FWString = QFutureWatcher< QString >; + + auto* handler = new CalamaresUtils::GeoIP::Handler( + CalamaresUtils::getString( geoip, "style" ), + CalamaresUtils::getString( geoip, "url" ), + CalamaresUtils::getString( geoip, "selector" ) ); + auto* future = new FWString(); + connect( future, &FWString::finished, [f=future, h=handler]() + { + cDebug() << "GeoIP result for welcome=" << f->future().result(); + f->deleteLater(); + delete h; + } ); + future->setFuture( handler->queryRaw() ); + } } Calamares::RequirementsList WelcomeViewStep::checkRequirements() diff --git a/src/modules/welcome/welcome.conf b/src/modules/welcome/welcome.conf index 52492ffef..fcef45a59 100644 --- a/src/modules/welcome/welcome.conf +++ b/src/modules/welcome/welcome.conf @@ -47,3 +47,16 @@ requirements: # - storage - ram # - root + +# GeoIP checking +# +# This can be used to pre-select a language based on the country +# the user is currently in. It *assumes* that there's internet +# connectivity, though. Configuration is like in the locale module, +# but remember to use a URL that returns full data **and** to +# use a selector that will pick the country, not the timezone. + +geoip: + style: "xml" + url: "https://geoip.kde.org/v1/ubiquity" # extended XML format + selector: "CountryCode" # blank uses default, which is wrong From 2a448c057deef69aaa272dda53bc800097bb23e3 Mon Sep 17 00:00:00 2001 From: Adriaan de Groot Date: Fri, 10 May 2019 07:53:44 -0400 Subject: [PATCH 24/31] [welcome] Provide API for updating the country - Changing country will pre-select the language most likely for that country (it doesn't, yet, since we don't have the data). --- src/modules/welcome/WelcomeViewStep.cpp | 21 ++++++++++++++++++--- src/modules/welcome/WelcomeViewStep.h | 7 +++++++ 2 files changed, 25 insertions(+), 3 deletions(-) diff --git a/src/modules/welcome/WelcomeViewStep.cpp b/src/modules/welcome/WelcomeViewStep.cpp index 91745967e..0442a2d6c 100644 --- a/src/modules/welcome/WelcomeViewStep.cpp +++ b/src/modules/welcome/WelcomeViewStep.cpp @@ -126,9 +126,11 @@ WelcomeViewStep::setConfigurationMap( const QVariantMap& configurationMap ) CalamaresUtils::getString( geoip, "url" ), CalamaresUtils::getString( geoip, "selector" ) ); auto* future = new FWString(); - connect( future, &FWString::finished, [f=future, h=handler]() + connect( future, &FWString::finished, [view=this, f=future, h=handler]() { - cDebug() << "GeoIP result for welcome=" << f->future().result(); + QString countryResult = f->future().result(); + cDebug() << "GeoIP result for welcome=" << countryResult; + view->setCountry( countryResult ); f->deleteLater(); delete h; } ); @@ -136,7 +138,20 @@ WelcomeViewStep::setConfigurationMap( const QVariantMap& configurationMap ) } } -Calamares::RequirementsList WelcomeViewStep::checkRequirements() +Calamares::RequirementsList +WelcomeViewStep::checkRequirements() { return m_requirementsChecker->checkRequirements(); } + +void +WelcomeViewStep::setCountry( const QString& countryCode ) +{ + if ( countryCode.length() != 2 ) + { + cDebug() << "Unusable country code" << countryCode; + return; + } + + cDebug() << "TODO: update country" << countryCode; +} diff --git a/src/modules/welcome/WelcomeViewStep.h b/src/modules/welcome/WelcomeViewStep.h index 937cad246..7deed2167 100644 --- a/src/modules/welcome/WelcomeViewStep.h +++ b/src/modules/welcome/WelcomeViewStep.h @@ -54,6 +54,13 @@ public: void setConfigurationMap( const QVariantMap& configurationMap ) override; + /** @brief Sets the country that Calamares is running in. + * + * This (ideally) sets up language and locale settings that are right for + * the given 2-letter country code. + */ + void setCountry( const QString& ); + Calamares::RequirementsList checkRequirements() override; private: From 81499b22a1815ba1d38daa8d4064ae37b6940e4f Mon Sep 17 00:00:00 2001 From: Adriaan de Groot Date: Fri, 10 May 2019 10:57:50 -0400 Subject: [PATCH 25/31] [libcalamares] Fix build of tests - Link Qt::Xml publicly because the tests will need it as well. --- src/libcalamares/CMakeLists.txt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/libcalamares/CMakeLists.txt b/src/libcalamares/CMakeLists.txt index 585ab7b6b..ad1c7f336 100644 --- a/src/libcalamares/CMakeLists.txt +++ b/src/libcalamares/CMakeLists.txt @@ -14,6 +14,7 @@ configure_file( ${CMAKE_CURRENT_SOURCE_DIR}/../calamares/CalamaresVersion.h.in ${CMAKE_CURRENT_BINARY_DIR}/CalamaresVersion.h ) set( OPTIONAL_PRIVATE_LIBRARIES "" ) +set( OPTIONAL_PUBLIC_LIBRARIES "" ) set( libSources CppJob.cpp @@ -92,7 +93,7 @@ endif() find_package(Qt5 COMPONENTS Xml) if( Qt5Xml_FOUND ) list( APPEND libSources geoip/GeoIPXML.cpp ) - list( APPEND OPTIONAL_PRIVATE_LIBRARIES Qt5::Network Qt5::Xml ) + list( APPEND OPTIONAL_PUBLIC_LIBRARIES Qt5::Network Qt5::Xml ) endif() ### LIBRARY @@ -112,6 +113,7 @@ target_link_libraries( calamares LINK_PUBLIC ${YAMLCPP_LIBRARY} Qt5::Core + ${OPTIONAL_PUBLIC_LIBRARIES} ) install( TARGETS calamares From b490e30a5e0c5896f123f23d170eb4d23f10bb25 Mon Sep 17 00:00:00 2001 From: Adriaan de Groot Date: Fri, 10 May 2019 11:03:01 -0400 Subject: [PATCH 26/31] [welcome] Use the new locale lookup after GeoIP gets a 2-letter code --- src/modules/welcome/WelcomeViewStep.cpp | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/modules/welcome/WelcomeViewStep.cpp b/src/modules/welcome/WelcomeViewStep.cpp index 0442a2d6c..5f9bb4657 100644 --- a/src/modules/welcome/WelcomeViewStep.cpp +++ b/src/modules/welcome/WelcomeViewStep.cpp @@ -23,6 +23,7 @@ #include "checker/GeneralRequirements.h" #include "geoip/Handler.h" +#include "locale/Lookup.h" #include "modulesystem/ModuleManager.h" #include "utils/Logger.h" #include "utils/Variant.h" @@ -153,5 +154,12 @@ WelcomeViewStep::setCountry( const QString& countryCode ) return; } - cDebug() << "TODO: update country" << countryCode; + auto c_l = Calamares::countryData( countryCode ); + if ( c_l.first == QLocale::Country::AnyCountry ) + { + cDebug() << "Unusable country code" << countryCode; + return; + } + else + cDebug() << "Would like to select" << c_l; } From 18ed4c74efba8efc6919e27a87e1049122c91cc7 Mon Sep 17 00:00:00 2001 From: Adriaan de Groot Date: Fri, 10 May 2019 11:46:20 -0400 Subject: [PATCH 27/31] [libcalamares] Move more into the locale service - Use namespace CalamaresUtils::Locale consistently for this service. - Move locale-related non-GUI support code from the Welcome module to libcalamares; these are generally useful. Both Label (naming a locale) and LabelModel (managing a bunch of those Labels) have been moved. --- src/libcalamares/CMakeLists.txt | 3 +- .../LocaleLabel.cpp => locale/Label.cpp} | 16 ++++----- .../{utils/LocaleLabel.h => locale/Label.h} | 17 ++++----- .../locale/LabelModel.cpp} | 36 +++++++++---------- .../locale/LabelModel.h} | 36 +++++++++---------- src/libcalamares/locale/Lookup.cpp | 8 ++--- src/libcalamares/locale/Lookup.h | 9 ++--- src/modules/locale/LocalePage.cpp | 8 ++--- src/modules/welcome/CMakeLists.txt | 1 - src/modules/welcome/WelcomePage.cpp | 14 ++++++-- src/modules/welcome/WelcomePage.h | 18 ++++++++-- src/modules/welcome/WelcomeViewStep.cpp | 2 +- 12 files changed, 93 insertions(+), 75 deletions(-) rename src/libcalamares/{utils/LocaleLabel.cpp => locale/Label.cpp} (84%) rename src/libcalamares/{utils/LocaleLabel.h => locale/Label.h} (90%) rename src/{modules/welcome/LocaleModel.cpp => libcalamares/locale/LabelModel.cpp} (65%) rename src/{modules/welcome/LocaleModel.h => libcalamares/locale/LabelModel.h} (68%) diff --git a/src/libcalamares/CMakeLists.txt b/src/libcalamares/CMakeLists.txt index ad1c7f336..959b0a9db 100644 --- a/src/libcalamares/CMakeLists.txt +++ b/src/libcalamares/CMakeLists.txt @@ -31,6 +31,8 @@ set( libSources geoip/Handler.cpp # Locale-data service + locale/Label.cpp + locale/LabelModel.cpp locale/Lookup.cpp # Partition service @@ -40,7 +42,6 @@ set( libSources utils/CalamaresUtilsSystem.cpp utils/CommandList.cpp utils/Dirs.cpp - utils/LocaleLabel.cpp utils/Logger.cpp utils/PluginFactory.cpp utils/Retranslator.cpp diff --git a/src/libcalamares/utils/LocaleLabel.cpp b/src/libcalamares/locale/Label.cpp similarity index 84% rename from src/libcalamares/utils/LocaleLabel.cpp rename to src/libcalamares/locale/Label.cpp index 26480ef14..ca528dc75 100644 --- a/src/libcalamares/utils/LocaleLabel.cpp +++ b/src/libcalamares/locale/Label.cpp @@ -1,7 +1,7 @@ /* === This file is part of Calamares - === * * Copyright 2014-2015, Teo Mrnjavac - * Copyright 2017-2018, Adriaan de Groot + * Copyright 2017-2019, 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 @@ -17,12 +17,12 @@ * along with Calamares. If not, see . */ -#include "LocaleLabel.h" +#include "Label.h" -namespace CalamaresUtils +namespace CalamaresUtils::Locale { -LocaleLabel::LocaleLabel() +Label::Label() : m_locale( QLocale() ) { m_localeId = m_locale.name(); @@ -30,15 +30,15 @@ LocaleLabel::LocaleLabel() setLabels( QString(), LabelFormat::IfNeededWithCountry ); } -LocaleLabel::LocaleLabel( const QString& locale, LabelFormat format ) - : m_locale( LocaleLabel::getLocale( locale ) ) +Label::Label( const QString& locale, LabelFormat format ) + : m_locale( Label::getLocale( locale ) ) , m_localeId( locale ) { setLabels( locale, format ); } void -LocaleLabel::setLabels( const QString& locale, LabelFormat format ) +Label::setLabels( const QString& locale, LabelFormat format ) { //: language[name] (country[name]) QString longFormat = QObject::tr( "%1 (%2)" ); @@ -59,7 +59,7 @@ LocaleLabel::setLabels( const QString& locale, LabelFormat format ) m_englishLabel = needsCountryName ? longFormat.arg( englishName, QLocale::countryToString( m_locale.country() ) ) : englishName; } -QLocale LocaleLabel::getLocale( const QString& localeName ) +QLocale Label::getLocale( const QString& localeName ) { if ( localeName.contains( "@latin" ) ) { diff --git a/src/libcalamares/utils/LocaleLabel.h b/src/libcalamares/locale/Label.h similarity index 90% rename from src/libcalamares/utils/LocaleLabel.h rename to src/libcalamares/locale/Label.h index b56b29f33..a436d4c62 100644 --- a/src/libcalamares/utils/LocaleLabel.h +++ b/src/libcalamares/locale/Label.h @@ -1,7 +1,7 @@ /* === This file is part of Calamares - === * * Copyright 2014-2015, Teo Mrnjavac - * Copyright 2017-2018, Adriaan de Groot + * Copyright 2017-2019, 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 @@ -17,13 +17,14 @@ * along with Calamares. If not, see . */ -#ifndef UTILS_LOCALELABEL_H -#define UTILS_LOCALELABEL_H +#ifndef LOCALE_LABEL_H +#define LOCALE_LABEL_H #include #include -namespace CalamaresUtils +namespace CalamaresUtils {} +namespace CalamaresUtils::Locale { /** @@ -33,14 +34,14 @@ namespace CalamaresUtils * translation system) into QLocales, and also into consistent * human-readable text labels. */ -class LocaleLabel +class Label { public: /** @brief Formatting option for label -- add (country) to label. */ enum class LabelFormat { AlwaysWithCountry, IfNeededWithCountry } ; /** @brief Empty locale. This uses the system-default locale. */ - LocaleLabel(); + Label(); /** @brief Construct from a locale name. * @@ -48,13 +49,13 @@ public: * The @p format determines whether the country name is always present * in the label (human-readable form) or only if needed for disambiguation. */ - LocaleLabel( const QString& localeName, LabelFormat format = LabelFormat::IfNeededWithCountry ); + Label( const QString& localeName, LabelFormat format = LabelFormat::IfNeededWithCountry ); /** @brief Define a sorting order. * * English (@see isEnglish() -- it means en_US) is sorted at the top. */ - bool operator <( const LocaleLabel& other ) const + bool operator <( const Label& other ) const { return m_localeId < other.m_localeId; } diff --git a/src/modules/welcome/LocaleModel.cpp b/src/libcalamares/locale/LabelModel.cpp similarity index 65% rename from src/modules/welcome/LocaleModel.cpp rename to src/libcalamares/locale/LabelModel.cpp index 0ecf0fd1c..312d96121 100644 --- a/src/modules/welcome/LocaleModel.cpp +++ b/src/libcalamares/locale/LabelModel.cpp @@ -16,30 +16,33 @@ * along with Calamares. If not, see . */ -#include "LocaleModel.h" +#include "LabelModel.h" -LocaleModel::LocaleModel( const QStringList& locales, QObject* parent ) +namespace CalamaresUtils::Locale +{ + +LabelModel::LabelModel( const QStringList& locales, QObject* parent ) : QAbstractListModel( parent ) { Q_ASSERT( locales.count() > 0 ); m_locales.reserve( locales.count() ); for ( const auto& l : locales ) - m_locales.push_back( CalamaresUtils::LocaleLabel( l ) ); + m_locales.push_back( Label( l ) ); } -LocaleModel::~LocaleModel() +LabelModel::~LabelModel() { } int -LocaleModel::rowCount( const QModelIndex& ) const +LabelModel::rowCount( const QModelIndex& ) const { return m_locales.count(); } QVariant -LocaleModel::data( const QModelIndex& index, int role ) const +LabelModel::data( const QModelIndex& index, int role ) const { if ( ( role != LabelRole ) && ( role != EnglishLabelRole ) ) return QVariant(); @@ -59,8 +62,8 @@ LocaleModel::data( const QModelIndex& index, int role ) const } } -const CalamaresUtils::LocaleLabel& -LocaleModel::locale( int row ) +const Label& +LabelModel::locale( int row ) { if ( ( row < 0 ) || ( row >= m_locales.count() ) ) { @@ -73,7 +76,7 @@ LocaleModel::locale( int row ) } int -LocaleModel::find( std::function predicate ) const +LabelModel::find( std::function predicate ) const { for ( int row = 0; row < m_locales.count() ; ++row ) { @@ -84,26 +87,21 @@ LocaleModel::find( std::function predicate ) const } int -LocaleModel::find( std::function predicate ) const +LabelModel::find( std::function predicate ) const { - return find( [&]( const LocaleLabel& l ) + return find( [&]( const Label& l ) { return predicate( l.locale() ); } ); } int -LocaleModel::find( const QLocale& locale ) const +LabelModel::find( const QLocale& locale ) const { - return find( [&]( const LocaleLabel& l ) + return find( [&]( const Label& l ) { return locale == l.locale(); } ); } -void -LocaleTwoColumnDelegate::paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const -{ - QStyledItemDelegate::paint( painter, option, index ); - option.widget->style()->drawItemText( painter, option.rect, Qt::AlignRight | Qt::AlignVCenter, option.palette, false, index.data( LocaleModel::EnglishLabelRole ).toString() ); -} +} // namespace diff --git a/src/modules/welcome/LocaleModel.h b/src/libcalamares/locale/LabelModel.h similarity index 68% rename from src/modules/welcome/LocaleModel.h rename to src/libcalamares/locale/LabelModel.h index b1566d336..092ee638a 100644 --- a/src/modules/welcome/LocaleModel.h +++ b/src/libcalamares/locale/LabelModel.h @@ -16,28 +16,31 @@ * along with Calamares. If not, see . */ -#ifndef WELCOME_LOCALEMODEL_H -#define WELCOME_LOCALEMODEL_H +#ifndef LOCALE_LABELMODEL_H +#define LOCALE_LABELMODEL_H + +#include "DllMacro.h" +#include "Label.h" #include -#include #include -#include "utils/LocaleLabel.h" -class LocaleModel : public QAbstractListModel +namespace CalamaresUtils {} +namespace CalamaresUtils::Locale +{ + +DLLEXPORT class LabelModel : public QAbstractListModel { public: - using LocaleLabel = CalamaresUtils::LocaleLabel; - enum { LabelRole = Qt::DisplayRole, EnglishLabelRole = Qt::UserRole + 1 }; - LocaleModel( const QStringList& locales, QObject* parent = nullptr ); - virtual ~LocaleModel() override; + LabelModel( const QStringList& locales, QObject* parent = nullptr ); + virtual ~LabelModel() override; int rowCount( const QModelIndex& parent ) const override; @@ -48,26 +51,19 @@ public: * This is the backing data for the model; if @p row is out-of-range, * returns a reference to en_US. */ - const LocaleLabel& locale( int row ); + const Label& locale( int row ); /** @brief Searches for an item that matches @p predicate * * Returns the row number of the first match, or -1 if there isn't one. */ int find( std::function predicate ) const; - int find( std::function predicate ) const; + int find( std::function predicate ) const; int find( const QLocale& ) const; private: - QVector< LocaleLabel > m_locales; -} ; - -class LocaleTwoColumnDelegate : public QStyledItemDelegate -{ -public: - using QStyledItemDelegate::QStyledItemDelegate; - - void paint( QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index ) const override; + QVector< Label > m_locales; } ; +} // namespace #endif diff --git a/src/libcalamares/locale/Lookup.cpp b/src/libcalamares/locale/Lookup.cpp index d38d417d4..a096bc679 100644 --- a/src/libcalamares/locale/Lookup.cpp +++ b/src/libcalamares/locale/Lookup.cpp @@ -20,7 +20,7 @@ #include "CountryData_p.cpp" -namespace Calamares +namespace CalamaresUtils::Locale { struct TwoChar @@ -35,7 +35,7 @@ struct TwoChar cc2 = code[1].toLatin1(); } } - + char cc1; char cc2; }; @@ -44,7 +44,7 @@ static const CountryData* lookup( TwoChar c ) { if ( !c.cc1 ) return nullptr; - + const CountryData* p = std::find_if(country_data_table, country_data_table + country_data_size, [c=c]( const CountryData& d ){ return (d.cc1 == c.cc1) && (d.cc2 == c.cc2); } ); @@ -52,7 +52,7 @@ static const CountryData* lookup( TwoChar c ) return nullptr; return p; } - + QLocale::Country countryForCode(const QString& code) { const CountryData* p = lookup( TwoChar( code ) ); diff --git a/src/libcalamares/locale/Lookup.h b/src/libcalamares/locale/Lookup.h index 976c4dc21..5712a1120 100644 --- a/src/libcalamares/locale/Lookup.h +++ b/src/libcalamares/locale/Lookup.h @@ -24,25 +24,26 @@ #include #include -namespace Calamares +namespace CalamaresUtils {} +namespace CalamaresUtils::Locale { /* All the functions in this file do lookups of locale data * based on CLDR tables; these are lookups that you can't (easily) * do with just QLocale (e.g. from 2-letter country code to a likely * locale). */ - + /// @brief Map a 2-letter code to a Country, or AnyCountry if not found DLLEXPORT QLocale::Country countryForCode( const QString& code ); /** @brief Map a Country to a Language, or AnyLanguage if not found - * + * * This is a *likely* language for the given country, based on the * CLDR tables. For instance, this maps Belgium to Dutch. */ DLLEXPORT QLocale::Language languageForCountry( QLocale::Country country ); /// @brief Map a 2-letter code to a Language, or AnyLanguage if not found DLLEXPORT QLocale::Language languageForCountry( const QString& code ); - + /// @brief Get both Country and Language for a 2-letter code DLLEXPORT QPair< QLocale::Country, QLocale::Language > countryData( const QString& code ); /// @brief Get a likely locale for a 2-letter country code diff --git a/src/modules/locale/LocalePage.cpp b/src/modules/locale/LocalePage.cpp index c8076866e..f6cdba436 100644 --- a/src/modules/locale/LocalePage.cpp +++ b/src/modules/locale/LocalePage.cpp @@ -27,8 +27,8 @@ #include "LCLocaleDialog.h" #include "Settings.h" +#include "locale/Label.h" #include "utils/CalamaresUtilsGui.h" -#include "utils/LocaleLabel.h" #include "utils/Logger.h" #include "utils/Retranslator.h" @@ -387,10 +387,10 @@ LocalePage::init( const QString& initialRegion, std::pair< QString, QString > LocalePage::prettyLocaleStatus( const LocaleConfiguration& lc ) const { - using CalamaresUtils::LocaleLabel; + using CalamaresUtils::Locale::Label; - LocaleLabel lang( lc.language(), LocaleLabel::LabelFormat::AlwaysWithCountry ); - LocaleLabel num( lc.lc_numeric, LocaleLabel::LabelFormat::AlwaysWithCountry ); + Label lang( lc.language(), Label::LabelFormat::AlwaysWithCountry ); + Label num( lc.lc_numeric, Label::LabelFormat::AlwaysWithCountry ); return std::make_pair< QString, QString >( tr( "The system language will be set to %1." ).arg( lang.label() ), diff --git a/src/modules/welcome/CMakeLists.txt b/src/modules/welcome/CMakeLists.txt index e6ddd2bd7..e25b7f5d0 100644 --- a/src/modules/welcome/CMakeLists.txt +++ b/src/modules/welcome/CMakeLists.txt @@ -27,7 +27,6 @@ calamares_add_plugin( welcome EXPORT_MACRO PLUGINDLLEXPORT_PRO SOURCES ${CHECKER_SOURCES} - LocaleModel.cpp WelcomeViewStep.cpp WelcomePage.cpp UI diff --git a/src/modules/welcome/WelcomePage.cpp b/src/modules/welcome/WelcomePage.cpp index 65a475310..11a17c2f0 100644 --- a/src/modules/welcome/WelcomePage.cpp +++ b/src/modules/welcome/WelcomePage.cpp @@ -21,16 +21,16 @@ #include "WelcomePage.h" #include "ui_WelcomePage.h" -#include "LocaleModel.h" #include "checker/CheckerContainer.h" #include "Branding.h" #include "CalamaresVersion.h" #include "Settings.h" #include "ViewManager.h" + +#include "locale/LabelModel.h" #include "modulesystem/ModuleManager.h" #include "utils/CalamaresUtilsGui.h" -#include "utils/LocaleLabel.h" #include "utils/Logger.h" #include "utils/Retranslator.h" @@ -131,7 +131,7 @@ WelcomePage::initLanguages() ui->languageWidget->clear(); ui->languageWidget->setInsertPolicy( QComboBox::InsertAtBottom ); - m_languages = new LocaleModel( QString( CALAMARES_TRANSLATION_LANGUAGES ).split( ';') ); + m_languages = new CalamaresUtils::Locale::LabelModel( QString( CALAMARES_TRANSLATION_LANGUAGES ).split( ';') ); ui->languageWidget->setModel( m_languages ); ui->languageWidget->setItemDelegate( new LocaleTwoColumnDelegate( ui->languageWidget ) ); @@ -261,3 +261,11 @@ bool WelcomePage::verdict() const { return m_checkingWidget->verdict(); } + + +void +LocaleTwoColumnDelegate::paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const +{ + QStyledItemDelegate::paint( painter, option, index ); + option.widget->style()->drawItemText( painter, option.rect, Qt::AlignRight | Qt::AlignVCenter, option.palette, false, index.data( CalamaresUtils::Locale::LabelModel::EnglishLabelRole ).toString() ); +} diff --git a/src/modules/welcome/WelcomePage.h b/src/modules/welcome/WelcomePage.h index ec689735b..53a30d95b 100644 --- a/src/modules/welcome/WelcomePage.h +++ b/src/modules/welcome/WelcomePage.h @@ -20,6 +20,9 @@ #ifndef WELCOMEPAGE_H #define WELCOMEPAGE_H +#include "locale/LabelModel.h" + +#include #include namespace Ui @@ -28,7 +31,6 @@ class WelcomePage; } class CheckerContainer; -class LocaleModel; class WelcomePage : public QWidget { @@ -53,7 +55,19 @@ private: Ui::WelcomePage* ui; CheckerContainer* m_checkingWidget; - LocaleModel *m_languages; + CalamaresUtils::Locale::LabelModel *m_languages; }; +/** @brief Delegate to display language information in two columns. + * + * Displays the native language name and the English language name. + */ +class LocaleTwoColumnDelegate : public QStyledItemDelegate +{ +public: + using QStyledItemDelegate::QStyledItemDelegate; + + void paint( QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index ) const override; +} ; + #endif // WELCOMEPAGE_H diff --git a/src/modules/welcome/WelcomeViewStep.cpp b/src/modules/welcome/WelcomeViewStep.cpp index 5f9bb4657..97b378330 100644 --- a/src/modules/welcome/WelcomeViewStep.cpp +++ b/src/modules/welcome/WelcomeViewStep.cpp @@ -154,7 +154,7 @@ WelcomeViewStep::setCountry( const QString& countryCode ) return; } - auto c_l = Calamares::countryData( countryCode ); + auto c_l = CalamaresUtils::Locale::countryData( countryCode ); if ( c_l.first == QLocale::Country::AnyCountry ) { cDebug() << "Unusable country code" << countryCode; From 76b45a2740e41f2f6fadfd99ecee9feefd29bb8a Mon Sep 17 00:00:00 2001 From: Adriaan de Groot Date: Fri, 10 May 2019 11:50:01 -0400 Subject: [PATCH 28/31] [libcalamares] const-data retrieval is const for LabelModel --- src/libcalamares/locale/LabelModel.cpp | 2 +- src/libcalamares/locale/LabelModel.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libcalamares/locale/LabelModel.cpp b/src/libcalamares/locale/LabelModel.cpp index 312d96121..90475cb0e 100644 --- a/src/libcalamares/locale/LabelModel.cpp +++ b/src/libcalamares/locale/LabelModel.cpp @@ -63,7 +63,7 @@ LabelModel::data( const QModelIndex& index, int role ) const } const Label& -LabelModel::locale( int row ) +LabelModel::locale( int row ) const { if ( ( row < 0 ) || ( row >= m_locales.count() ) ) { diff --git a/src/libcalamares/locale/LabelModel.h b/src/libcalamares/locale/LabelModel.h index 092ee638a..c807e6016 100644 --- a/src/libcalamares/locale/LabelModel.h +++ b/src/libcalamares/locale/LabelModel.h @@ -51,7 +51,7 @@ public: * This is the backing data for the model; if @p row is out-of-range, * returns a reference to en_US. */ - const Label& locale( int row ); + const Label& locale( int row ) const; /** @brief Searches for an item that matches @p predicate * From 18579524312687e0c013b8bb5cf6bebb18b082b1 Mon Sep 17 00:00:00 2001 From: Adriaan de Groot Date: Fri, 10 May 2019 12:06:10 -0400 Subject: [PATCH 29/31] [libcalamares] Add convenience accessor for translations - Which translations are available is a global property of Calamares itself, not of the plugins, so getting the model of available translations should live there. Move the relevant code (which is simple) from the Welcome module. --- src/libcalamares/locale/LabelModel.cpp | 8 ++++++++ src/libcalamares/locale/LabelModel.h | 14 +++++++++++++- src/modules/welcome/WelcomePage.cpp | 2 +- 3 files changed, 22 insertions(+), 2 deletions(-) diff --git a/src/libcalamares/locale/LabelModel.cpp b/src/libcalamares/locale/LabelModel.cpp index 90475cb0e..ac931620d 100644 --- a/src/libcalamares/locale/LabelModel.cpp +++ b/src/libcalamares/locale/LabelModel.cpp @@ -18,6 +18,8 @@ #include "LabelModel.h" +#include "CalamaresVersion.h" // For the list of translations + namespace CalamaresUtils::Locale { @@ -104,4 +106,10 @@ LabelModel::find( const QLocale& locale ) const } ); } +LabelModel* const availableTranslations() +{ + static LabelModel model( QString( CALAMARES_TRANSLATION_LANGUAGES ).split( ';') ); + return &model; +} + } // namespace diff --git a/src/libcalamares/locale/LabelModel.h b/src/libcalamares/locale/LabelModel.h index c807e6016..6b4f41343 100644 --- a/src/libcalamares/locale/LabelModel.h +++ b/src/libcalamares/locale/LabelModel.h @@ -30,7 +30,7 @@ namespace CalamaresUtils {} namespace CalamaresUtils::Locale { -DLLEXPORT class LabelModel : public QAbstractListModel +class DLLEXPORT LabelModel : public QAbstractListModel { public: enum @@ -65,5 +65,17 @@ private: QVector< Label > m_locales; } ; +/** @brief Returns a model with all available translations. + * + * The translations are set when Calamares is compiled; the list + * is provided by CMake via the CALAMARES_TRANSLATION_LANGUAGES + * #define. + * + * This model is a singleton and can be shared. + * + * NOTE: While the model is not typed const, it should be. Do not modify. + */ +DLLEXPORT LabelModel* const availableTranslations(); + } // namespace #endif diff --git a/src/modules/welcome/WelcomePage.cpp b/src/modules/welcome/WelcomePage.cpp index 11a17c2f0..c7d169c92 100644 --- a/src/modules/welcome/WelcomePage.cpp +++ b/src/modules/welcome/WelcomePage.cpp @@ -131,7 +131,7 @@ WelcomePage::initLanguages() ui->languageWidget->clear(); ui->languageWidget->setInsertPolicy( QComboBox::InsertAtBottom ); - m_languages = new CalamaresUtils::Locale::LabelModel( QString( CALAMARES_TRANSLATION_LANGUAGES ).split( ';') ); + m_languages = CalamaresUtils::Locale::availableTranslations(); ui->languageWidget->setModel( m_languages ); ui->languageWidget->setItemDelegate( new LocaleTwoColumnDelegate( ui->languageWidget ) ); From 03f88b3ed6cbf9155f6f62d941e9fd165c0e3202 Mon Sep 17 00:00:00 2001 From: Adriaan de Groot Date: Fri, 10 May 2019 14:44:54 -0400 Subject: [PATCH 30/31] [libcalamares] Support looking up translation by 2-letter country - Looks for an available translation by 2-letter country code and returns the row for it. --- src/libcalamares/locale/Label.h | 12 ++++++++++++ src/libcalamares/locale/LabelModel.cpp | 15 +++++++++++++++ src/libcalamares/locale/LabelModel.h | 3 +++ 3 files changed, 30 insertions(+) diff --git a/src/libcalamares/locale/Label.h b/src/libcalamares/locale/Label.h index a436d4c62..65befc6b4 100644 --- a/src/libcalamares/locale/Label.h +++ b/src/libcalamares/locale/Label.h @@ -92,6 +92,18 @@ public: return m_locale.name(); } + /// @brief Convenience accessor to the language part of the locale + QLocale::Language language() const + { + return m_locale.language(); + } + + /// @brief Convenience accessor to the country part (if any) of the locale + QLocale::Country country() const + { + return m_locale.country(); + } + /** @brief Get a Qt locale for the given @p localeName * * This special-cases `sr@latin`, which is used as a translation diff --git a/src/libcalamares/locale/LabelModel.cpp b/src/libcalamares/locale/LabelModel.cpp index ac931620d..543417212 100644 --- a/src/libcalamares/locale/LabelModel.cpp +++ b/src/libcalamares/locale/LabelModel.cpp @@ -18,6 +18,8 @@ #include "LabelModel.h" +#include "Lookup.h" + #include "CalamaresVersion.h" // For the list of translations namespace CalamaresUtils::Locale @@ -106,6 +108,19 @@ LabelModel::find( const QLocale& locale ) const } ); } +int +LabelModel::find( const QString& countryCode ) const +{ + if ( countryCode.length() != 2 ) + return -1; + + auto c_l = countryData( countryCode ); + int r = find( [&]( const Label& l ){ return ( l.language() == c_l.second ) && ( l.country() == c_l.first ); } ); + if ( r >= 0 ) + return r; + return find( [&]( const Label& l ){ return l.language() == c_l.second; } ); +} + LabelModel* const availableTranslations() { static LabelModel model( QString( CALAMARES_TRANSLATION_LANGUAGES ).split( ';') ); diff --git a/src/libcalamares/locale/LabelModel.h b/src/libcalamares/locale/LabelModel.h index 6b4f41343..178f76343 100644 --- a/src/libcalamares/locale/LabelModel.h +++ b/src/libcalamares/locale/LabelModel.h @@ -59,7 +59,10 @@ public: */ int find( std::function predicate ) const; int find( std::function predicate ) const; + /// @brief Looks for an item using the same locale, -1 if there isn't one int find( const QLocale& ) const; + /// @brief Looks for an item that best matches the 2-letter country code + int find( const QString& countryCode ) const; private: QVector< Label > m_locales; From f18f9dcd14c043b95abfbd4e4319611b66aa9223 Mon Sep 17 00:00:00 2001 From: Adriaan de Groot Date: Fri, 10 May 2019 15:02:12 -0400 Subject: [PATCH 31/31] [welcome] Lookup GeoIP language and pass to language widget - FIXES #934 - Whether this is really wanted depends on the distro, and I'm not 100% convinced the likely tags from Unicode are correct (or it'd take a lot more data). In any case, starting Calamares in "NL" gets me "nl_NL" as translation; presumably starting it in "BE" will get me that as well (what about Les Wallons?) - This also shows off that it's a real hack to have so much program logic in the *widget* parts of each ViewStep. Longer-term, a lot of functionality should go to the ViewStep itself, which will then control the UI. --- src/modules/welcome/WelcomePage.cpp | 10 +++++++++- src/modules/welcome/WelcomePage.h | 2 ++ src/modules/welcome/WelcomeViewStep.cpp | 8 +++++++- 3 files changed, 18 insertions(+), 2 deletions(-) diff --git a/src/modules/welcome/WelcomePage.cpp b/src/modules/welcome/WelcomePage.cpp index c7d169c92..ae78aa8ff 100644 --- a/src/modules/welcome/WelcomePage.cpp +++ b/src/modules/welcome/WelcomePage.cpp @@ -257,11 +257,19 @@ WelcomePage::focusInEvent( QFocusEvent* e ) e->accept(); } -bool WelcomePage::verdict() const +bool +WelcomePage::verdict() const { return m_checkingWidget->verdict(); } +void +WelcomePage::externallySelectedLanguage( int row ) +{ + if ( ( row >= 0 ) && ( row < ui->languageWidget->count() ) ) + ui->languageWidget->setCurrentIndex( row ); +} + void LocaleTwoColumnDelegate::paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const diff --git a/src/modules/welcome/WelcomePage.h b/src/modules/welcome/WelcomePage.h index 53a30d95b..f05426d38 100644 --- a/src/modules/welcome/WelcomePage.h +++ b/src/modules/welcome/WelcomePage.h @@ -46,6 +46,8 @@ public: /// @brief Results of requirements checking bool verdict() const; + /// @brief Change the language from an external source. + void externallySelectedLanguage( int row ); protected: void focusInEvent( QFocusEvent* e ) override; //choose the child widget to focus diff --git a/src/modules/welcome/WelcomeViewStep.cpp b/src/modules/welcome/WelcomeViewStep.cpp index 97b378330..e115565b7 100644 --- a/src/modules/welcome/WelcomeViewStep.cpp +++ b/src/modules/welcome/WelcomeViewStep.cpp @@ -161,5 +161,11 @@ WelcomeViewStep::setCountry( const QString& countryCode ) return; } else - cDebug() << "Would like to select" << c_l; + { + int r = CalamaresUtils::Locale::availableTranslations()->find( countryCode ); + if ( r < 0 ) + cDebug() << "Unusable country code" << countryCode << "(no suitable translation)"; + if ( ( r >= 0 ) && m_widget ) + m_widget->externallySelectedLanguage( r ); + } }