changeset 257:60b94daf4d24

CMake: update irccd_define_plugin, closes #534 Also add a native debugging plugin.
author David Demelier <markand@malikania.fr>
date Tue, 13 Sep 2016 12:57:17 +0200
parents f04acabfbbe5
children c7d4e8c279a9
files cmake/IrccdOptions.cmake cmake/IrccdVersion.cmake cmake/function/IrccdDefinePlugin.cmake irccd/main.cpp lib/irccd/path.cpp lib/irccd/server.hpp plugins/CMakeLists.txt plugins/debugnative/main.cpp
diffstat 8 files changed, 377 insertions(+), 106 deletions(-) [+]
line wrap: on
line diff
--- a/cmake/IrccdOptions.cmake	Mon Sep 12 17:54:27 2016 +0200
+++ b/cmake/IrccdOptions.cmake	Tue Sep 13 12:57:17 2016 +0200
@@ -86,18 +86,6 @@
 option(WITH_MAN "Install man pages" ${DEFAULT_MAN})
 option(WITH_PKGCONFIG "Enable pkg-config file" ${DEFAULT_PKGCONFIG})
 
-# Build options for all plugins.
-foreach (plugin ${IRCCD_PLUGINS})
-    string(TOUPPER ${plugin} optname)
-    option(WITH_PLUGIN_${optname} "Enable ${plugin} plugin" On)
-
-    if (NOT WITH_PLUGIN_${optname})
-        set(WITH_PLUGIN_${optname}_MSG "No (disabled by user)")
-    else ()
-        set(WITH_PLUGIN_${optname}_MSG "Yes")
-    endif ()
-endforeach ()
-
 set(WITH_TEST_IRCHOST "127.0.0.1" CACHE STRING "IRC host for tests")
 set(WITH_TEST_IRCPORT 6667 CACHE STRING "IRC port for test")
 
--- a/cmake/IrccdVersion.cmake	Mon Sep 12 17:54:27 2016 +0200
+++ b/cmake/IrccdVersion.cmake	Tue Sep 13 12:57:17 2016 +0200
@@ -35,16 +35,3 @@
 set(IRCCD_RELEASE_DATE_MONTH 04)
 set(IRCCD_RELEASE_DATE_DAY 19)
 set(IRCCD_RELEASE_DATE "${IRCCD_RELEASE_DATE_YEAR}-${IRCCD_RELEASE_DATE_MONTH}-${IRCCD_RELEASE_DATE_DAY}")
-
-# All plugins.
-set(
-    IRCCD_PLUGINS
-    ask
-    auth
-    hangman
-    history
-    logger
-    plugin
-    roulette
-    CACHE INTERNAL ""
-)
--- a/cmake/function/IrccdDefinePlugin.cmake	Mon Sep 12 17:54:27 2016 +0200
+++ b/cmake/function/IrccdDefinePlugin.cmake	Tue Sep 13 12:57:17 2016 +0200
@@ -20,18 +20,146 @@
 # irccd_define_plugin
 # -------------------------------------------------------------------
 #
-# Define a JavaScript plugin, the file will be configured using configure_file and then installed.
+# irccd_define_plugin(
+#   NAME canonical plugin name
+#   TYPE JS or NATIVE
+#   DOCS documentation files in markdown
+#
+#   Options for TYPE JS:
+#
+#   SCRIPT absolute path to the Javascript file (ending with .js)
+#
+#   Options for TYPE NATIVE:
+#
+#   SOURCES c++ source files
 #
-# Parameters:
-#    file        The plugin full file path
+# Create a Javascript or Native plugin.
+#
+# The NAME parameter identifies the plugin. The same name will be used for the
+# plugin filename.
+#
+# Both Javascript and native plugins are supported specified by the TYPE
+# parameter to JS or NATIVE respectively. For Javascript plugin, a unique file
+# must be given as SCRIPT parameter. For native plugins, any source files can
+# be given as SOURCES parameter.
+#
+# Additional documentation can be built in markdown and installed along the
+# plugin using DOCS parameter.
+#
+# A CMake option is also created in the form OPTION_<PLG> where PLG is the
+# uppercase NAME value.
 #
-macro(irccd_define_plugin file)
-    get_filename_component(name ${file} NAME)
-    set(base ${IRCCD_FAKEROOTDIR}/${WITH_PLUGINDIR})
+
+function(_irccd_define_javascript_plugin)
+    if (NOT PLG_SCRIPT)
+        message(FATAL_ERROR "Missing SCRIPT parameter")
+    endif ()
+
+    get_filename_component(name ${PLG_SCRIPT} NAME)
+
+    configure_file(
+        ${PLG_SCRIPT}
+        ${IRCCD_FAKEROOTDIR}/${WITH_PLUGINDIR}/${name}
+    )
+
+    install(
+        FILES ${IRCCD_FAKEROOTDIR}/${WITH_PLUGINDIR}/${name}
+        COMPONENT ${PLG_NAME}
+        DESTINATION ${WITH_PLUGINDIR}
+    )
+
+    add_custom_target(
+        plugin-${PLG_NAME}
+        DEPENDS ${PLG_OUTPUT_DOC}
+    )
+endfunction()
+
+function(_irccd_define_native_plugin)
+    if (NOT PLG_SOURCES)
+        message(FATAL_ERROR "Missing SOURCES parameter")
+    endif ()
+
+    add_library(plugin-${PLG_NAME} MODULE ${PLG_SOURCES} ${PLG_OUTPUT_DOC})
+
+    # Move the target into the native plugin directory and rename it.
+    set_target_properties(
+        plugin-${PLG_NAME}
+        PROPERTIES
+            PREFIX ""
+            OUTPUT_NAME ${PLG_NAME}
+            LIBRARY_OUTPUT_DIRECTORY ${IRCCD_FAKEROOTDIR}/${WITH_NPLUGINDIR}
+    )
+    foreach (c ${CMAKE_CONFIGURATION_TYPES})
+        string(TOUPPER CONFIG ${c})
+        set_target_properties(
+            plugin-${PLG_NAME}
+            PROPERTIES
+                OUTPUT_NAME_${CONFIG} ${PLG_NAME}
+                LIBRARY_OUTPUT_DIRECTORY_${CONFIG} ${IRCCD_FAKEROOTDIR}/${WITH_NPLUGINDIR}
+        )
+    endforeach()
+    target_link_libraries(plugin-${PLG_NAME} libirccd)
+    install(
+        TARGETS plugin-${PLG_NAME}
+        COMPONENT ${PLG_NAME}
+        LIBRARY DESTINATION ${WITH_NPLUGINDIR}
+    )
+endfunction()
 
-    # Substitude variables in the JavaScript file.
-    configure_file(${file} ${base}/${name})
+function(irccd_define_plugin)
+    set(options "")
+    set(oneValueArgs NAME TYPE SCRIPT)
+    set(multiValueArgs DOCS SOURCES)
+
+    cmake_parse_arguments(PLG "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
+
+    if (NOT PLG_NAME)
+        message(FATAL_ERROR "Missing NAME parameter")
+    endif ()
+
+    string(TOUPPER ${PLG_NAME} PLG_UPPER_NAME)
+    option(WITH_PLUGIN_${PLG_UPPER_NAME} "Enable ${PLG_NAME} plugin" On)
+
+    if (NOT WITH_PLUGIN_${PLG_UPPER_NAME})
+        setg(WITH_PLUGIN_${PLG_UPPER_NAME}_MSG "No (disabled by user)")
+    else ()
+        setg(WITH_PLUGIN_${PLG_UPPER_NAME}_MSG "Yes")
+
+        # Optional documentation.
+        if (PLG_DOCS AND WITH_HTML)
+            set(basedocdir ${IRCCD_FAKEROOTDIR}/${WITH_DOCDIR})
+            set(PLG_OUTPUT_DOC ${basedocdir}/plugin/${PLG_NAME}.html)
+            file(RELATIVE_PATH baseurl ${basedocdir}/plugin ${basedocdir})
 
-    # Install the plugin file.
-    install(FILES ${base}/${name} DESTINATION ${WITH_PLUGINDIR})
-endmacro()
+            pandoc(
+                OUTPUT ${basedocdir}/plugin/${PLG_NAME}.html
+                SOURCES ${PLG_DOCS}
+                TEMPLATE ${resources_SOURCE_DIR}/template.html
+                DEPENDS
+                    ${resources_SOURCE_DIR}/template.html
+                    docs-resources
+                ARGS -Vguide
+                VARIABLE baseurl:${baseurl}
+                FROM markdown TO html5
+                STANTALONE MAKE_DIRECTORY TOC
+            )
+            install(
+                FILES ${basedocdir}/plugin/${PLG_NAME}.html
+                COMPONENT ${PLG_NAME}
+                DESTINATION ${WITH_DOCDIR}/plugin
+            )
+        endif ()
+
+        if (PLG_TYPE MATCHES "JS")
+            _irccd_define_javascript_plugin()
+        elseif (PLG_TYPE MATCHES "NATIVE")
+            _irccd_define_native_plugin()
+        else ()
+            message(FATAL_ERROR "Invalid TYPE given, must be JS or NATIVE")
+        endif ()
+
+        # Component grouping in installer.
+        setg(CPACK_COMPONENT_${PLG_UPPER_NAME}_GROUP "Plugins")
+        setg(CPACK_COMPONENT_${PLG_UPPER_NAME}_DESCRIPTION "Install ${PLG_NAME} plugin.")
+    endif ()
+endfunction()
--- a/irccd/main.cpp	Mon Sep 12 17:54:27 2016 +0200
+++ b/irccd/main.cpp	Tue Sep 13 12:57:17 2016 +0200
@@ -265,7 +265,13 @@
         return 1;
     }
 
+    /*
+     * Assign instance to nullptr to force deletion of irccd and all its
+     * associated objects before any other static global values such as
+     * loggers.
+     */
     instance->run();
+    instance = nullptr;
 
     return 0;
 }
--- a/lib/irccd/path.cpp	Mon Sep 12 17:54:27 2016 +0200
+++ b/lib/irccd/path.cpp	Tue Sep 13 12:57:17 2016 +0200
@@ -520,7 +520,8 @@
         list.push_back(clean(systemPlugins()));
         break;
     case PathNativePlugins:
-        list.push_back(clean(systemPlugins()));
+        list.push_back(clean(fs::cwd()));
+        list.push_back(clean(systemNativePlugins()));
         break;
     default:
         break;
--- a/lib/irccd/server.hpp	Mon Sep 12 17:54:27 2016 +0200
+++ b/lib/irccd/server.hpp	Tue Sep 13 12:57:17 2016 +0200
@@ -79,14 +79,6 @@
 };
 
 /**
- * \brief Some variables that are needed in many places internally.
- */
-class Cache {
-public:
-
-};
-
-/**
  * \brief Channel event.
  */
 class ChannelModeEvent {
--- a/plugins/CMakeLists.txt	Mon Sep 12 17:54:27 2016 +0200
+++ b/plugins/CMakeLists.txt	Tue Sep 13 12:57:17 2016 +0200
@@ -18,68 +18,30 @@
 
 project(plugins)
 
-add_custom_target(
-    all-plugins ALL
-    COMMENT "Irccd plugins"
-)
-
-set_target_properties(
-    all-plugins
-    PROPERTIES
-        FOLDER meta
+set(
+    IRCCD_PLUGINS
+    ask
+    auth
+    hangman
+    history
+    logger
+    plugin
+    roulette
+    CACHE INTERNAL ""
 )
 
 foreach (plugin ${IRCCD_PLUGINS})
-    string(TOUPPER ${plugin} optname)
-
-    if (WITH_PLUGIN_${optname})
-        # 1. Configure the plugin and install it.
-        irccd_define_plugin(${plugin}/${plugin}.js)
-
-        # 2. Build documentation.
-        if (WITH_HTML)
-            set(basedocdir ${IRCCD_FAKEROOTDIR}/${WITH_DOCDIR})
-            file(RELATIVE_PATH baseurl ${basedocdir}/plugin ${basedocdir})
-
-            pandoc(
-                OUTPUT ${basedocdir}/plugin/${plugin}.html
-                SOURCES ${plugin}/${plugin}.md
-                TEMPLATE ${resources_SOURCE_DIR}/template.html
-                DEPENDS
-                    ${resources_SOURCE_DIR}/template.html
-                    docs-resources
-                ARGS -Vguide
-                VARIABLE baseurl:${baseurl}
-                FROM markdown TO html5
-                STANTALONE MAKE_DIRECTORY TOC
-            )
+    irccd_define_plugin(
+        NAME ${plugin}
+        TYPE JS
+        SCRIPT ${plugins_SOURCE_DIR}/${plugin}/${plugin}.js
+        DOCS ${plugins_SOURCE_DIR}/${plugin}/${plugin}.md
+    )
+endforeach ()
 
-            list(APPEND outputs ${basedocdir}/plugin/${plugin}.html)
-            install(
-                FILES ${basedocdir}/plugin/${plugin}.html
-                COMPONENT ${plugin}
-                DESTINATION ${WITH_DOCDIR}/plugin
-            )
-            string(TOUPPER ${plugin} CMP)
-            setg(CPACK_COMPONENT_${CMP}_DESCRIPTION "Install ${plugin}.")
-            setg(CPACK_COMPONENT_${CMP}_GROUP "Plugins")
-        endif ()
-
-        add_custom_target(
-            plugin-${plugin}
-            SOURCES
-                ${outputs}
-                ${plugin}/${plugin}.js
-                ${plugin}/${plugin}.md
-        )
-
-        set_target_properties(
-            plugin-${plugin}
-            PROPERTIES
-                PROJECT_LABEL ${plugin}
-                FOLDER plugins
-        )
-
-        add_dependencies(all-plugins plugin-${plugin})
-    endif ()
-endforeach ()
+# Debug plugins.
+irccd_define_plugin(
+    NAME debugnative
+    TYPE NATIVE
+    SOURCES ${plugins_SOURCE_DIR}/debugnative/main.cpp
+)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/plugins/debugnative/main.cpp	Tue Sep 13 12:57:17 2016 +0200
@@ -0,0 +1,207 @@
+/*
+ * main.cpp -- native plugin for debugging
+ *
+ * Copyright (c) 2013-2016 David Demelier <markand@malikania.fr>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <iostream>
+
+#include <irccd/irccd.hpp>
+#include <irccd/logger.hpp>
+#include <irccd/plugin-dynlib.hpp>
+#include <irccd/server.hpp>
+#include <irccd/util.hpp>
+
+using namespace irccd;
+
+extern "C" {
+
+DYNLIB_EXPORT void irccd_onChannelMode(Irccd &, const ChannelModeEvent &event)
+{
+    log::info() << "plugin debugnative: onChannelMode event\n";
+    log::info() << "plugin debugnative:   server: " << event.server->name() << std::endl;
+    log::info() << "plugin debugnative:   origin: " << event.origin << std::endl;
+    log::info() << "plugin debugnative:   channel: " << event.channel << std::endl;
+    log::info() << "plugin debugnative:   mode: " << event.mode << std::endl;
+    log::info() << "plugin debugnative:   argument: " << event.argument << std::endl;
+}
+
+DYNLIB_EXPORT void irccd_onChannelNotice(Irccd &, const ChannelNoticeEvent &event)
+{
+    log::info() << "plugin debugnative: onChannelNotice event\n";
+    log::info() << "plugin debugnative:   server: " << event.server->name() << std::endl;
+    log::info() << "plugin debugnative:   origin: " << event.origin << std::endl;
+    log::info() << "plugin debugnative:   channel: " << event.channel << std::endl;
+    log::info() << "plugin debugnative:   message: " << event.message << std::endl;
+}
+
+DYNLIB_EXPORT void irccd_onCommand(Irccd &, const MessageEvent &event)
+{
+    log::info() << "plugin debugnative: onCommand event\n";
+    log::info() << "plugin debugnative:   server: " << event.server->name() << std::endl;
+    log::info() << "plugin debugnative:   origin: " << event.origin << std::endl;
+    log::info() << "plugin debugnative:   channel: " << event.channel << std::endl;
+    log::info() << "plugin debugnative:   message: " << event.message << std::endl;
+}
+
+DYNLIB_EXPORT void irccd_onConnect(Irccd &, const ConnectEvent &event)
+{
+    log::info() << "plugin debugnative: onConnect event\n";
+    log::info() << "plugin debugnative:   server: " << event.server->name() << std::endl;
+}
+
+DYNLIB_EXPORT void irccd_onInvite(Irccd &, const InviteEvent &event)
+{
+    log::info() << "plugin debugnative: onInvite event\n";
+    log::info() << "plugin debugnative:   server: " << event.server->name() << std::endl;
+    log::info() << "plugin debugnative:   origin: " << event.origin << std::endl;
+    log::info() << "plugin debugnative:   channel: " << event.channel << std::endl;
+    log::info() << "plugin debugnative:   nickname: " << event.nickname << std::endl;
+}
+
+DYNLIB_EXPORT void irccd_onJoin(Irccd &, const JoinEvent &event)
+{
+    log::info() << "plugin debugnative: onJoin event\n";
+    log::info() << "plugin debugnative:   server: " << event.server->name() << std::endl;
+    log::info() << "plugin debugnative:   origin: " << event.origin << std::endl;
+    log::info() << "plugin debugnative:   channel: " << event.channel << std::endl;
+}
+
+DYNLIB_EXPORT void irccd_onKick(Irccd &, const KickEvent &event)
+{
+    log::info() << "plugin debugnative: onKick event\n";
+    log::info() << "plugin debugnative:   server: " << event.server->name() << std::endl;
+    log::info() << "plugin debugnative:   origin: " << event.origin << std::endl;
+    log::info() << "plugin debugnative:   channel: " << event.channel << std::endl;
+    log::info() << "plugin debugnative:   target: " << event.target << std::endl;
+    log::info() << "plugin debugnative:   reason: " << event.reason << std::endl;
+}
+
+DYNLIB_EXPORT void irccd_onLoad(Irccd &, DynlibPlugin &)
+{
+    log::info() << "plugin debugnative: onLoad event\n";
+}
+
+DYNLIB_EXPORT void irccd_onMessage(Irccd &, const MessageEvent &event)
+{
+
+    log::info() << "plugin debugnative: onMessage event\n";
+    log::info() << "plugin debugnative:   server: " << event.server->name() << std::endl;
+    log::info() << "plugin debugnative:   origin: " << event.origin << std::endl;
+    log::info() << "plugin debugnative:   channel: " << event.channel << std::endl;
+    log::info() << "plugin debugnative:   message: " << event.message << std::endl;
+}
+
+DYNLIB_EXPORT void irccd_onMe(Irccd &, const MeEvent &event)
+{
+    log::info() << "plugin debugnative: onMe event\n";
+    log::info() << "plugin debugnative:   server: " << event.server->name() << std::endl;
+    log::info() << "plugin debugnative:   origin: " << event.origin << std::endl;
+    log::info() << "plugin debugnative:   channel: " << event.channel << std::endl;
+    log::info() << "plugin debugnative:   message: " << event.message << std::endl;
+}
+
+DYNLIB_EXPORT void irccd_onMode(Irccd &, const ModeEvent &event)
+{
+    log::info() << "plugin debugnative: onMode event\n";
+    log::info() << "plugin debugnative:   server: " << event.server->name() << std::endl;
+    log::info() << "plugin debugnative:   origin: " << event.origin << std::endl;
+    log::info() << "plugin debugnative:   mode: " << event.mode << std::endl;
+}
+
+DYNLIB_EXPORT void irccd_onNames(Irccd &, const NamesEvent &event)
+{
+    log::info() << "plugin debugnative: onNames event\n";
+    log::info() << "plugin debugnative:   server: " << event.server->name() << std::endl;
+    log::info() << "plugin debugnative:   channel: " << event.channel << std::endl;
+    log::info() << "plugin debugnative:   names: "
+                << util::join(event.names.begin(), event.names.end(), ", ")
+                << std::endl;
+}
+
+DYNLIB_EXPORT void irccd_onNick(Irccd &, const NickEvent &event)
+{
+    log::info() << "plugin debugnative: onNick event\n";
+    log::info() << "plugin debugnative:   server: " << event.server->name() << std::endl;
+    log::info() << "plugin debugnative:   origin: " << event.origin << std::endl;
+    log::info() << "plugin debugnative:   nickname: " << event.nickname << std::endl;
+}
+
+DYNLIB_EXPORT void irccd_onNotice(Irccd &, const NoticeEvent &event)
+{
+    log::info() << "plugin debugnative: onNotice event\n";
+    log::info() << "plugin debugnative:   server: " << event.server->name() << std::endl;
+    log::info() << "plugin debugnative:   origin: " << event.origin << std::endl;
+    log::info() << "plugin debugnative:   message: " << event.message << std::endl;
+}
+
+DYNLIB_EXPORT void irccd_onPart(Irccd &, const PartEvent &event)
+{
+    log::info() << "plugin debugnative: onPart event\n";
+    log::info() << "plugin debugnative:   server: " << event.server->name() << std::endl;
+    log::info() << "plugin debugnative:   origin: " << event.origin << std::endl;
+    log::info() << "plugin debugnative:   channel: " << event.channel << std::endl;
+    log::info() << "plugin debugnative:   reason: " << event.reason << std::endl;
+}
+
+DYNLIB_EXPORT void irccd_onQuery(Irccd &, const QueryEvent &event)
+{
+    log::info() << "plugin debugnative: onQuery event\n";
+    log::info() << "plugin debugnative:   server: " << event.server->name() << std::endl;
+    log::info() << "plugin debugnative:   origin: " << event.origin << std::endl;
+    log::info() << "plugin debugnative:   message: " << event.message << std::endl;
+}
+
+DYNLIB_EXPORT void irccd_onQueryCommand(Irccd &, const QueryEvent &event)
+{
+    log::info() << "plugin debugnative: onQueryCommand event\n";
+    log::info() << "plugin debugnative:   server: " << event.server->name() << std::endl;
+    log::info() << "plugin debugnative:   origin: " << event.origin << std::endl;
+    log::info() << "plugin debugnative:   message: " << event.message << std::endl;
+}
+
+DYNLIB_EXPORT void irccd_onReload(Irccd &, DynlibPlugin &)
+{
+    log::info() << "plugin debugnative: onReload event\n";
+}
+
+DYNLIB_EXPORT void irccd_onTopic(Irccd &, const TopicEvent &event)
+{
+    log::info() << "plugin debugnative: onTopic event\n";
+    log::info() << "plugin debugnative:   server: " << event.server->name() << std::endl;
+    log::info() << "plugin debugnative:   origin: " << event.origin << std::endl;
+    log::info() << "plugin debugnative:   channel: " << event.channel << std::endl;
+    log::info() << "plugin debugnative:   topic: " << event.topic << std::endl;
+}
+
+DYNLIB_EXPORT void irccd_onUnload(Irccd &, DynlibPlugin &)
+{
+    log::info() << "plugin debugnative: onUnload event\n";
+}
+
+DYNLIB_EXPORT void irccd_onWhois(Irccd &, const WhoisEvent &event)
+{
+    log::info() << "plugin debugnative: onWhois event\n";
+    log::info() << "plugin debugnative:   server: " << event.server->name() << std::endl;
+    log::info() << "plugin debugnative:   nick: " << event.whois.nick << std::endl;
+    log::info() << "plugin debugnative:   user: " << event.whois.user << std::endl;
+    log::info() << "plugin debugnative:   host: " << event.whois.host << std::endl;
+    log::info() << "plugin debugnative:   channels: "
+                << util::join(event.whois.channels.begin(),
+                              event.whois.channels.end(), ", ")
+                << std::endl;
+}
+
+} // !C