From 7f173de361dfd4251c37949d231856b52e02cb0c Mon Sep 17 00:00:00 2001
From: Adriaan de Groot <groot@kde.org>
Date: Mon, 30 Dec 2024 23:38:45 +0100
Subject: [PATCH] [libcalamares] Add generic(-ish) variant-to-python code

This is code duplicated between the two implementation
directories (to be taken out shortly). It isn't generic
in a template-sense, but it does use the types and
support functions defined in the implementation-specific
PythonTypes header.
---
 src/libcalamares/CMakeLists.txt     |   1 +
 src/libcalamares/python/Variant.cpp | 114 ++++++++++++++++++++++++++++
 src/libcalamares/python/Variant.h   |  40 ++++++++++
 3 files changed, 155 insertions(+)
 create mode 100644 src/libcalamares/python/Variant.cpp
 create mode 100644 src/libcalamares/python/Variant.h

diff --git a/src/libcalamares/CMakeLists.txt b/src/libcalamares/CMakeLists.txt
index f8effad178..55ffaa34f0 100644
--- a/src/libcalamares/CMakeLists.txt
+++ b/src/libcalamares/CMakeLists.txt
@@ -136,6 +136,7 @@ if(WITH_PYTHON)
         target_sources(calamares PRIVATE pyboost/PythonHelper.cpp pyboost/PythonJob.cpp pyboost/PythonJobApi.cpp)
         target_link_libraries(calamares PRIVATE Python::Python Boost::python)
     endif()
+    target_sources(calamares PRIVATE python/Variant.cpp)
 endif()
 
 ### OPTIONAL GeoIP XML support
diff --git a/src/libcalamares/python/Variant.cpp b/src/libcalamares/python/Variant.cpp
new file mode 100644
index 0000000000..22bf51c3cd
--- /dev/null
+++ b/src/libcalamares/python/Variant.cpp
@@ -0,0 +1,114 @@
+/* === This file is part of Calamares - <https://calamares.io> ===
+ *
+ *   SPDX-FileCopyrightText: 2014 Teo Mrnjavac <teo@kde.org>
+ *   SPDX-FileCopyrightText: 2018-2020, 2024 Adriaan de Groot <groot@kde.org>
+ *   SPDX-License-Identifier: GPL-3.0-or-later
+ *
+ *   Calamares is Free Software: see the License-Identifier above.
+ *
+ */
+
+#include "Variant.h"
+
+#include "PythonTypes.h"
+#include "compat/Variant.h"
+
+namespace
+{
+
+Calamares::Python::List
+variantListToPyList( const QVariantList& variantList )
+{
+    Calamares::Python::List pyList;
+    for ( const QVariant& variant : variantList )
+    {
+        pyList.append( Calamares::Python::variantToPyObject( variant ) );
+    }
+    return pyList;
+}
+
+Calamares::Python::Dictionary
+variantHashToPyDict( const QVariantHash& variantHash )
+{
+    Calamares::Python::Dictionary pyDict;
+    for ( auto it = variantHash.constBegin(); it != variantHash.constEnd(); ++it )
+    {
+        pyDict[ Calamares::Python::String( it.key().toStdString() ) ] = Calamares::Python::variantToPyObject( it.value() );
+    }
+    return pyDict;
+}
+
+}
+
+namespace Calamares
+{
+namespace Python
+{
+
+Dictionary
+variantMapToPyDict( const QVariantMap& variantMap )
+{
+    Calamares::Python::Dictionary pyDict;
+    for ( auto it = variantMap.constBegin(); it != variantMap.constEnd(); ++it )
+    {
+        pyDict[ Calamares::Python::String( it.key().toStdString() ) ] = Calamares::Python::variantToPyObject( it.value() );
+    }
+    return pyDict;
+}
+
+Object
+variantToPyObject( const QVariant& variant )
+{
+    QT_WARNING_PUSH
+    QT_WARNING_DISABLE_CLANG( "-Wswitch-enum" )
+
+    // 49 enumeration values not handled
+    switch ( Calamares::typeOf( variant ) )
+    {
+    case Calamares::MapVariantType:
+        return variantMapToPyDict( variant.toMap() );
+
+    case Calamares::HashVariantType:
+        return variantHashToPyDict( variant.toHash() );
+
+    case Calamares::ListVariantType:
+    case Calamares::StringListVariantType:
+        return variantListToPyList( variant.toList() );
+
+    case Calamares::IntVariantType:
+        return Python::Integer( variant.toInt() );
+    case Calamares::UIntVariantType:
+        return Python::Integer( variant.toUInt() );
+
+    case Calamares::LongLongVariantType:
+        return Python::Integer( variant.toLongLong() );
+    case Calamares::ULongLongVariantType:
+        return Python::Integer( variant.toULongLong() );
+
+    case Calamares::DoubleVariantType:
+        return Python::Float( variant.toDouble() );
+
+    case Calamares::CharVariantType:
+#if QT_VERSION < QT_VERSION_CHECK( 6, 0, 0 )
+#else
+    // In Qt6, QChar is also available and different from CharVariantType
+    case QMetaType::Type::QChar:
+#endif
+    case Calamares::StringVariantType:
+        return Calamares::Python::String( variant.toString().toStdString() );
+
+    case Calamares::BoolVariantType:
+        return Python::Boolean( variant.toBool() );
+
+#if QT_VERSION < QT_VERSION_CHECK( 6, 0, 0 )
+    case QVariant::Invalid:
+#endif
+    default:
+        return Python::None();
+    }
+    QT_WARNING_POP
+}
+
+
+    }
+}
diff --git a/src/libcalamares/python/Variant.h b/src/libcalamares/python/Variant.h
new file mode 100644
index 0000000000..88a5ea65d3
--- /dev/null
+++ b/src/libcalamares/python/Variant.h
@@ -0,0 +1,40 @@
+/* === This file is part of Calamares - <https://calamares.io> ===
+ *
+ *   SPDX-FileCopyrightText: 2014 Teo Mrnjavac <teo@kde.org>
+ *   SPDX-FileCopyrightText: 2018-2020, 2024 Adriaan de Groot <groot@kde.org>
+ *   SPDX-License-Identifier: GPL-3.0-or-later
+ *
+ *   Calamares is Free Software: see the License-Identifier above.
+ *
+ */
+
+#ifndef CALAMARES_PYTHONVARIANT_H
+#define CALAMARES_PYTHONVARIANT_H
+
+/**
+ * @file Support for turning QVariant into Python types, and vice-versa
+ *
+ * These are helper-functions for converting variants (e.g. values
+ * in GlobalStorage, or loaded from YAML) into Python. This is not
+ * public API and is used only inside the Python-job-support code.
+ */
+
+#include "PythonTypes.h"
+
+#include <QStringList>
+#include <QVariant>
+#include <QVariantMap>
+
+
+namespace Calamares
+{
+namespace Python __attribute__( ( visibility( "hidden" ) ) )
+{
+
+Dictionary variantMapToPyDict( const QVariantMap& variantMap );
+Object variantToPyObject( const QVariant& variant ); ///< More generic version of variantMapToPyDict
+
+}
+}
+
+#endif
-- 
GitLab