Remove the plugin loader mechanism for VFS backends

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>
This commit is contained in:
Kevin Ottens 2020-12-10 14:40:25 +01:00
parent 7e5f81ea81
commit 201dbd54db
No known key found for this signature in database
GPG key ID: 074BBBCB8DECC9E2
10 changed files with 34 additions and 194 deletions

View 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)

View file

@ -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);
}
}

View file

@ -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")

View file

@ -17,7 +17,6 @@
*/
#include "vfs.h"
#include "plugin.h"
#include "version.h"
#include "syncjournaldb.h"
@ -28,6 +27,15 @@
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;
qCCritical(lcPlugin) << "Could not load plugin: not existant" << name;
return nullptr;
}
QPluginLoader loader(pluginPath);
auto plugin = loader.instance();
if (!plugin) {
qCCritical(lcPlugin) << "Could not load plugin" << pluginPath << loader.errorString();
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;
}

View 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) \
}

View 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)

View file

@ -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()

View file

@ -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}"
)

View file

@ -152,3 +152,5 @@ Vfs::AvailabilityResult VfsSuffix::availability(const QString &folderPath)
}
} // namespace OCC
OCC_DEFINE_VFS_FACTORY("suffix", OCC::VfsSuffix)

View 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