Remove the plugin loader mechanism for VFS backends
authorKevin Ottens <kevin.ottens@nextcloud.com>
Thu, 10 Dec 2020 13:40:25 +0000 (14:40 +0100)
committerKevin Ottens <kevin.ottens@nextcloud.com>
Tue, 15 Dec 2020 09:59:24 +0000 (10:59 +0100)
We will have all the code in public anyway so it can just be compiled
in. Thus no need to go through the plugin loading dance. Replaced the
loading with factory functions. Kept mostly the same structure
otherwise.

Signed-off-by: Kevin Ottens <kevin.ottens@nextcloud.com>
src/common/common.cmake
src/common/plugin.cpp [deleted file]
src/common/plugin.h [deleted file]
src/common/vfs.cpp
src/common/vfs.h
src/libsync/CMakeLists.txt
src/libsync/vfs/CMakeLists.txt [deleted file]
src/libsync/vfs/suffix/CMakeLists.txt [deleted file]
src/libsync/vfs/suffix/vfs_suffix.cpp
src/libsync/vfs/suffix/vfs_suffix.h

index 5c7cd52c902bfe5b20d5776c6cd245b4e7f0abfc..82437cd04ebe7edd3dc5aa829de8be4ffea707b4 100644 (file)
@@ -11,8 +11,6 @@ set(common_SOURCES
     ${CMAKE_CURRENT_LIST_DIR}/remotepermissions.cpp
     ${CMAKE_CURRENT_LIST_DIR}/vfs.cpp
     ${CMAKE_CURRENT_LIST_DIR}/pinstate.cpp
-    ${CMAKE_CURRENT_LIST_DIR}/plugin.cpp
     ${CMAKE_CURRENT_LIST_DIR}/syncfilestatus.cpp
 )
 
-configure_file(${CMAKE_CURRENT_LIST_DIR}/vfspluginmetadata.json.in ${CMAKE_CURRENT_BINARY_DIR}/vfspluginmetadata.json)
diff --git a/src/common/plugin.cpp b/src/common/plugin.cpp
deleted file mode 100644 (file)
index 7e705d9..0000000
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * Copyright (C) by Dominik Schmidt <dschmidt@owncloud.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library 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
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-#include "plugin.h"
-
-#include "config.h"
-
-namespace OCC {
-
-PluginFactory::~PluginFactory() = default;
-
-QString pluginFileName(const QString &type, const QString &name)
-{
-    return QStringLiteral("%1sync_%2_%3")
-        .arg(QStringLiteral(APPLICATION_EXECUTABLE), type, name);
-}
-
-}
diff --git a/src/common/plugin.h b/src/common/plugin.h
deleted file mode 100644 (file)
index 3d28f7d..0000000
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * Copyright (C) by Dominik Schmidt <dschmidt@owncloud.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library 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
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-#pragma once
-
-#include "ocsynclib.h"
-#include <QObject>
-
-namespace OCC {
-
-class OCSYNC_EXPORT PluginFactory
-{
-public:
-    virtual ~PluginFactory();
-    virtual QObject* create(QObject* parent) = 0;
-};
-
-template<class PluginClass>
-class DefaultPluginFactory : public PluginFactory
-{
-public:
-    QObject* create(QObject *parent) override
-    {
-        return new PluginClass(parent);
-    }
-};
-
-/// Return the expected name of a plugin, for use with QPluginLoader
-QString pluginFileName(const QString &type, const QString &name);
-
-}
-
-Q_DECLARE_INTERFACE(OCC::PluginFactory, "org.owncloud.PluginFactory")
index 8c5c53d7b86014afac26490ad0827de69482c5bf..b1bdb5324f325f553502449486a94d6cdc01ed06 100644 (file)
@@ -17,7 +17,6 @@
  */
 
 #include "vfs.h"
-#include "plugin.h"
 #include "version.h"
 #include "syncjournaldb.h"
 
 
 using namespace OCC;
 
+using MetaObjectHash = QHash<QString, Vfs::Factory>;
+Q_GLOBAL_STATIC(MetaObjectHash, vfsFactoryHash);
+
+void Vfs::registerPlugin(const QString &name, Factory factory)
+{
+    Q_ASSERT(!vfsFactoryHash()->contains(name));
+    vfsFactoryHash()->insert(name, factory);
+}
+
 Vfs::Vfs(QObject* parent)
     : QObject(parent)
 {
@@ -150,33 +158,9 @@ bool OCC::isVfsPluginAvailable(Vfs::Mode mode)
     auto name = modeToPluginName(mode);
     if (name.isEmpty())
         return false;
-    auto pluginPath = pluginFileName(QStringLiteral("vfs"), name);
-    QPluginLoader loader(pluginPath);
 
-    auto basemeta = loader.metaData();
-    if (basemeta.isEmpty() || !basemeta.contains(QStringLiteral("IID"))) {
-        qCDebug(lcPlugin) << "Plugin doesn't exist" << loader.fileName();
-        return false;
-    }
-    if (basemeta[QStringLiteral("IID")].toString() != QLatin1String("org.owncloud.PluginFactory")) {
-        qCWarning(lcPlugin) << "Plugin has wrong IID" << loader.fileName() << basemeta[QStringLiteral("IID")];
-        return false;
-    }
-
-    auto metadata = basemeta[QStringLiteral("MetaData")].toObject();
-    if (metadata[QStringLiteral("type")].toString() != QLatin1String("vfs")) {
-        qCWarning(lcPlugin) << "Plugin has wrong type" << loader.fileName() << metadata[QStringLiteral("type")];
-        return false;
-    }
-    if (metadata[QStringLiteral("version")].toString() != QStringLiteral(MIRALL_VERSION_STRING)) {
-        qCWarning(lcPlugin) << "Plugin has wrong version" << loader.fileName() << metadata[QStringLiteral("version")];
-        return false;
-    }
-
-    // Attempting to load the plugin is essential as it could have dependencies that
-    // can't be resolved and thus not be available after all.
-    if (!loader.load()) {
-        qCWarning(lcPlugin) << "Plugin failed to load:" << loader.errorString();
+    if (!vfsFactoryHash()->contains(name)) {
+        qCDebug(lcPlugin) << "Plugin isn't registered:" << name;
         return false;
     }
 
@@ -201,32 +185,24 @@ std::unique_ptr<Vfs> OCC::createVfsFromPlugin(Vfs::Mode mode)
     auto name = modeToPluginName(mode);
     if (name.isEmpty())
         return nullptr;
-    auto pluginPath = pluginFileName(QStringLiteral("vfs"), name);
 
     if (!isVfsPluginAvailable(mode)) {
-        qCCritical(lcPlugin) << "Could not load plugin: not existant or bad metadata" << pluginPath;
-        return nullptr;
-    }
-
-    QPluginLoader loader(pluginPath);
-    auto plugin = loader.instance();
-    if (!plugin) {
-        qCCritical(lcPlugin) << "Could not load plugin" << pluginPath << loader.errorString();
+        qCCritical(lcPlugin) << "Could not load plugin: not existant" << name;
         return nullptr;
     }
 
-    auto factory = qobject_cast<PluginFactory *>(plugin);
+    const auto factory = vfsFactoryHash()->value(name);
     if (!factory) {
-        qCCritical(lcPlugin) << "Plugin" << loader.fileName() << "does not implement PluginFactory";
+        qCCritical(lcPlugin) << "Could not load plugin" << name;
         return nullptr;
     }
 
-    auto vfs = std::unique_ptr<Vfs>(qobject_cast<Vfs *>(factory->create(nullptr)));
+    auto vfs = std::unique_ptr<Vfs>(qobject_cast<Vfs *>(factory()));
     if (!vfs) {
-        qCCritical(lcPlugin) << "Plugin" << loader.fileName() << "does not create a Vfs instance";
+        qCCritical(lcPlugin) << "Plugin" << name << "does not create a Vfs instance";
         return nullptr;
     }
 
-    qCInfo(lcPlugin) << "Created VFS instance from plugin" << pluginPath;
+    qCInfo(lcPlugin) << "Created VFS instance for:" << name;
     return vfs;
 }
index c11f59bb2834d0e368820120533fc2fb4fc30c4a..66fae7e4b2417e01bea35e7b02af9842eb5abbf7 100644 (file)
@@ -14,6 +14,7 @@
 #pragma once
 
 #include <QObject>
+#include <QCoreApplication>
 #include <QScopedPointer>
 #include <QSharedPointer>
 
@@ -111,6 +112,9 @@ public:
     using AvailabilityResult = Result<VfsItemAvailability, AvailabilityError>;
 
 public:
+    using Factory = Vfs* (*)();
+    static void registerPlugin(const QString &name, Factory factory);
+
     explicit Vfs(QObject* parent = nullptr);
     virtual ~Vfs();
 
@@ -319,3 +323,13 @@ OCSYNC_EXPORT Vfs::Mode bestAvailableVfsMode();
 OCSYNC_EXPORT std::unique_ptr<Vfs> createVfsFromPlugin(Vfs::Mode mode);
 
 } // namespace OCC
+
+#define OCC_DEFINE_VFS_FACTORY(name, Type) \
+    static_assert (std::is_base_of<OCC::Vfs, Type>::value, "Please define VFS factories only for OCC::Vfs subclasses"); \
+    namespace { \
+    void initPlugin() \
+    { \
+        OCC::Vfs::registerPlugin(QStringLiteral(name), []() -> OCC::Vfs * { return new Type; }); \
+    } \
+    Q_COREAPP_STARTUP_FUNCTION(initPlugin) \
+    }
index 72d2b26bf93a3bdda49015419a0d2d585b06ebe6..35a4a9300be21798f05020d4f38098a7d1940afd 100644 (file)
@@ -58,6 +58,7 @@ set(libsync_SRCS
     creds/abstractcredentials.cpp
     creds/credentialscommon.cpp
     creds/keychainchunk.cpp
+    vfs/suffix/vfs_suffix.cpp
 )
 
 if(TOKEN_AUTH_ONLY)
@@ -138,6 +139,3 @@ if(NOT BUILD_OWNCLOUD_OSX_BUNDLE)
 else()
     install(TARGETS ${synclib_NAME} DESTINATION ${OWNCLOUD_OSX_BUNDLE}/Contents/MacOS)
 endif()
-
-
-add_subdirectory(vfs)
diff --git a/src/libsync/vfs/CMakeLists.txt b/src/libsync/vfs/CMakeLists.txt
deleted file mode 100644 (file)
index fec473b..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-# Globbing for plugins has a problem with in-source builds
-# that create directories for the build.
-#file(GLOB VIRTUAL_FILE_SYSTEM_PLUGINS RELATIVE ${CMAKE_CURRENT_LIST_DIR} "*")
-
-list(APPEND VIRTUAL_FILE_SYSTEM_PLUGINS "suffix" "win")
-
-foreach(vfsPlugin ${VIRTUAL_FILE_SYSTEM_PLUGINS})
-    set(vfsPluginPath ${vfsPlugin})
-    get_filename_component(vfsPluginName ${vfsPlugin} NAME)
-    if (NOT IS_ABSOLUTE ${vfsPlugin})
-        set(vfsPluginPath "${CMAKE_CURRENT_LIST_DIR}/${vfsPlugin}")
-    endif()
-    if(NOT IS_DIRECTORY ${vfsPluginPath})
-        continue()
-    endif()
-
-    add_subdirectory(${vfsPluginPath} ${vfsPluginName})
-
-    if(UNIT_TESTING AND IS_DIRECTORY "${vfsPluginPath}/test")
-        add_subdirectory("${vfsPluginPath}/test" "${vfsPluginName}_test")
-        message(STATUS "Added vfsPlugin with tests: ${vfsPluginName}")
-    else()
-        message(STATUS "Added vfsPlugin without tests: ${vfsPluginName}")
-    endif()
-endforeach()
diff --git a/src/libsync/vfs/suffix/CMakeLists.txt b/src/libsync/vfs/suffix/CMakeLists.txt
deleted file mode 100644 (file)
index 3765e02..0000000
+++ /dev/null
@@ -1,34 +0,0 @@
-add_library("${synclib_NAME}_vfs_suffix" SHARED
-    vfs_suffix.cpp
-)
-
-target_link_libraries("${synclib_NAME}_vfs_suffix"
-    "${synclib_NAME}"
-)
-
-set_target_properties("${synclib_NAME}_vfs_suffix" PROPERTIES
-    LIBRARY_OUTPUT_DIRECTORY ${BIN_OUTPUT_DIRECTORY}
-    RUNTIME_OUTPUT_DIRECTORY ${BIN_OUTPUT_DIRECTORY}
-    PREFIX ""
-    AUTOMOC TRUE
-)
-
-if(APPLE)
-    # for being loadable when client run from build dir
-    set(vfs_buildoutputdir "${BIN_OUTPUT_DIRECTORY}/${OWNCLOUD_OSX_BUNDLE}/Contents/PlugIns/")
-    set_target_properties("${synclib_NAME}_vfs_suffix"
-        PROPERTIES
-        LIBRARY_OUTPUT_DIRECTORY ${vfs_buildoutputdir}
-        RUNTIME_OUTPUT_DIRECTORY ${vfs_buildoutputdir}
-    )
-    # For being lodable when client run from install dir (after make macdeployqt)
-    set(vfs_installdir "${LIB_INSTALL_DIR}/../PlugIns")
-else()
-    set(vfs_installdir "${PLUGINDIR}")
-endif()
-
-INSTALL(TARGETS "${synclib_NAME}_vfs_suffix"
-  LIBRARY DESTINATION "${vfs_installdir}"
-  RUNTIME DESTINATION "${vfs_installdir}"
-)
-
index be64b62a6b023d351a1cd1ddf03158ecc0dfcc6d..357d5c88ea112a0857bc59b7b8696a984ff5753d 100644 (file)
@@ -152,3 +152,5 @@ Vfs::AvailabilityResult VfsSuffix::availability(const QString &folderPath)
 }
 
 } // namespace OCC
+
+OCC_DEFINE_VFS_FACTORY("suffix", OCC::VfsSuffix)
index ce70c2ebbbef34270d1b559446cac36722f19e92..3feca6ea06fe3f744358d72db4ade1efcfea6bb9 100644 (file)
@@ -17,7 +17,6 @@
 #include <QScopedPointer>
 
 #include "common/vfs.h"
-#include "common/plugin.h"
 
 namespace OCC {
 
@@ -61,11 +60,4 @@ protected:
     void startImpl(const VfsSetupParams &params) override;
 };
 
-class SuffixVfsPluginFactory : public QObject, public DefaultPluginFactory<VfsSuffix>
-{
-    Q_OBJECT
-    Q_PLUGIN_METADATA(IID "org.owncloud.PluginFactory" FILE "vfspluginmetadata.json")
-    Q_INTERFACES(OCC::PluginFactory)
-};
-
 } // namespace OCC