# HG changeset patch # User David Demelier # Date 1500556361 -7200 # Node ID 0b156b82b8c10ed97a70b775faa1fbb9ed190c1f # Parent daf3aa8b2ddbb17d115988dd7ec694f133fcd53d Irccd: rework of paths, closes #611 diff -r daf3aa8b2ddb -r 0b156b82b8c1 CMakeLists.txt --- a/CMakeLists.txt Thu Jul 27 16:44:57 2017 +0200 +++ b/CMakeLists.txt Thu Jul 20 15:12:41 2017 +0200 @@ -156,6 +156,7 @@ ${CMAKE_SOURCE_DIR}/CONTRIBUTE.md ${CMAKE_SOURCE_DIR}/CREDITS.md ${CMAKE_SOURCE_DIR}/INSTALL.md + ${CMAKE_SOURCE_DIR}/MIGRATING.md ${CMAKE_SOURCE_DIR}/README.md ${CMAKE_SOURCE_DIR}/STYLE.md ) diff -r daf3aa8b2ddb -r 0b156b82b8c1 MIGRATING.md --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/MIGRATING.md Thu Jul 20 15:12:41 2017 +0200 @@ -0,0 +1,27 @@ +IRC Client Daemon MIGRATING +=========================== + +This document is a small guide to help you migrating to a next major version. + +Migrating from 2.x to 3.x +------------------------- + +### CMake options + + - WITH_CONFDIR has been renamed to WITH_SYSCONFDIR. + +### Paths + + - The default plugins path has been changed from **share/irccd/plugins** to + **libexec/irccd/plugins**. + +### Plugin configuration + +The following properties in `Irccd.Plugin` has been renamed: + + - cachePath renamed to paths.cache, + - configPath renamed to paths.config, + - dataPath renamed to paths.data. + +Note: these paths are no more automatically detected and set with the new + `[paths]` and `[paths.]` sections. diff -r daf3aa8b2ddb -r 0b156b82b8c1 cmake/IrccdOptions.cmake --- a/cmake/IrccdOptions.cmake Thu Jul 27 16:44:57 2017 +0200 +++ b/cmake/IrccdOptions.cmake Thu Jul 20 15:12:41 2017 +0200 @@ -38,12 +38,14 @@ # Options that controls both installations and the irccd runtime: # # WITH_BINDIR Binary directory for irccd, irccdctl -# WITH_PLUGINDIR Path where plugins must be installed +# WITH_CACHEDIR Path where to store temporary files +# WITH_CMAKEDIR Path where to install CMake configuration files +# WITH_DATADIR Path for data files # WITH_DOCDIR Path where to install documentation # WITH_MANDIR Path where to install manuals -# WITH_CONFDIR Path where to search configuration files -# WITH_CACHEDIR Path where to store temporary files # WITH_PKGCONFIGDIR Path where to install pkg-config files +# WITH_PLUGINDIR Path where plugins must be installed +# WITH_SYSCONFDIR Path where to install configuration files # WITH_SYSTEMDDIR Path where to install systemd unit file # @@ -84,38 +86,17 @@ # set(WITH_BINDIR "bin" CACHE STRING "Binary directory") +set(WITH_CACHEDIR "var/cache/irccd" CACHE STRING "Cache directory") +set(WITH_CMAKEDIR "lib/cmake" CACHE STRING "Directory for CMake modules") +set(WITH_DATADIR "share/irccd" CACHE STRING "Directory for additional data") +set(WITH_DOCDIR "share/doc/irccd" CACHE STRING "Documentation directory") set(WITH_MANDIR "share/man" CACHE STRING "Man directory") -set(WITH_CONFDIR "etc" CACHE STRING "Configuration directory") -set(WITH_CMAKEDIR "lib/cmake" CACHE STRING "Directory for CMake modules") set(WITH_PKGCONFIGDIR "lib/pkgconfig" CACHE STRING "Directory for pkg-config file") +set(WITH_PLUGINDIR "libexec/irccd/plugins" CACHE STRING "Module prefix where to install") +set(WITH_SYSCONFDIR "etc" CACHE STRING "Configuration directory") set(WITH_SYSTEMDDIR "/usr/lib/systemd/system" CACHE STRING "Absolute path where to install systemd files") # -# On Windows, we install the applcation like C:/Program Files/irccd so do not append irccd to the -# directories again. -# -if (WIN32) - set(WITH_DATADIR "share" CACHE STRING "Data directory") - set(WITH_CACHEDIR "var" CACHE STRING "Temporary files directory") - set(WITH_PLUGINDIR "share/plugins" CACHE STRING "Module prefix where to install") - set(WITH_DOCDIR "share/doc" CACHE STRING "Documentation directory") -else () - set(WITH_DATADIR "share/irccd" CACHE STRING "Data directory") - set(WITH_CACHEDIR "var/irccd" CACHE STRING "Temporary files directory") - set(WITH_PLUGINDIR "share/irccd/plugins" CACHE STRING "Module prefix where to install") - set(WITH_DOCDIR "share/doc/irccd" CACHE STRING "Documentation directory") -endif () - -# -# Check if any of these path is absolute and raise an error if true. -# -foreach (d WITH_BINDIR WITH_CACHEDIR WITH_DATADIR WITH_CONFDIR WITH_PLUGINDIR) - if (IS_ABSOLUTE ${${d}}) - message(FATAL_ERROR "${d} can not be absolute (${${d}} given)") - endif () -endforeach () - -# # Internal dependencies. # ------------------------------------------------------------------- # diff -r daf3aa8b2ddb -r 0b156b82b8c1 cmake/IrccdSystem.cmake --- a/cmake/IrccdSystem.cmake Thu Jul 27 16:44:57 2017 +0200 +++ b/cmake/IrccdSystem.cmake Thu Jul 20 15:12:41 2017 +0200 @@ -83,6 +83,8 @@ set(IRCCD_SYSTEM_MAC TRUE) elseif (CMAKE_SYSTEM_NAME MATCHES "FreeBSD") set(IRCCD_SYSTEM_FREEBSD TRUE) +elseif (CMAKE_SYSTEM_NAME MATCHES "DragonFly") + set(IRCCD_SYSTEM_DRAGONFLYBSD TRUE) elseif (CMAKE_SYSTEM_NAME MATCHES "NetBSD") set(IRCCD_SYSTEM_NETBSD TRUE) elseif (CMAKE_SYSTEM_NAME MATCHES "OpenBSD") @@ -263,4 +265,7 @@ ${CMAKE_BINARY_DIR}/irccd/sysconfig.hpp ) -include_directories(${CMAKE_BINARY_DIR}) +include_directories( + ${CMAKE_BINARY_DIR} + ${CMAKE_BINARY_DIR}/irccd +) diff -r daf3aa8b2ddb -r 0b156b82b8c1 cmake/function/IrccdDefinePlugin.cmake --- a/cmake/function/IrccdDefinePlugin.cmake Thu Jul 27 16:44:57 2017 +0200 +++ b/cmake/function/IrccdDefinePlugin.cmake Thu Jul 20 15:12:41 2017 +0200 @@ -86,7 +86,7 @@ install( TARGETS plugin-${PLG_NAME} COMPONENT ${PLG_NAME} - LIBRARY DESTINATION ${WITH_NPLUGINDIR} + LIBRARY DESTINATION ${WITH_PLUGINDIR} ) endfunction() diff -r daf3aa8b2ddb -r 0b156b82b8c1 cmake/internal/sysconfig.hpp.in --- a/cmake/internal/sysconfig.hpp.in Thu Jul 27 16:44:57 2017 +0200 +++ b/cmake/internal/sysconfig.hpp.in Thu Jul 20 15:12:41 2017 +0200 @@ -54,6 +54,7 @@ #cmakedefine IRCCD_SYSTEM_WINDOWS #cmakedefine IRCCD_SYSTEM_MAC #cmakedefine IRCCD_SYSTEM_FREEBSD +#cmakedefine IRCCD_SYSTEM_DRAGONFLYBSD #cmakedefine IRCCD_SYSTEM_NETBSD #cmakedefine IRCCD_SYSTEM_OPENBSD #cmakedefine IRCCD_SYSTEM_LINUX @@ -64,12 +65,11 @@ * ------------------------------------------------------------------ */ -#define WITH_BINDIR "@WITH_BINDIR@" -#define WITH_DATADIR "@WITH_DATADIR@" -#define WITH_CONFDIR "@WITH_CONFDIR@" -#define WITH_PLUGINDIR "@WITH_PLUGINDIR@" -#define WITH_NPLUGINDIR "@WITH_NPLUGINDIR@" -#define WITH_CACHEDIR "@WITH_CACHEDIR@" +#define WITH_CACHEDIR "@WITH_CACHEDIR@" +#define WITH_DATADIR "@WITH_DATADIR@" +#define WITH_BINDIR "@WITH_BINDIR@" +#define WITH_SYSCONFDIR "@WITH_SYSCONFDIR@" +#define WITH_PLUGINDIR "@WITH_PLUGINDIR@" #cmakedefine WITH_JS #cmakedefine WITH_SSL @@ -120,7 +120,7 @@ # define IRCCD_EXPORT # endif #else -# define IRCCD_EXPORT +# define IRCCD_EXPORT #endif #endif // !IRCCD_SYSCONFIG_H diff -r daf3aa8b2ddb -r 0b156b82b8c1 doc/examples/CMakeLists.txt --- a/doc/examples/CMakeLists.txt Thu Jul 27 16:44:57 2017 +0200 +++ b/doc/examples/CMakeLists.txt Thu Jul 20 15:12:41 2017 +0200 @@ -33,7 +33,7 @@ ${examples_SOURCE_DIR}/irccd.conf.sample ${examples_SOURCE_DIR}/irccdctl.conf.sample COMPONENT examples - DESTINATION ${WITH_CONFDIR} + DESTINATION ${WITH_SYSCONFDIR} ) setg(CPACK_COMPONENT_EXAMPLES_HIDDEN On) diff -r daf3aa8b2ddb -r 0b156b82b8c1 doc/html/api/module/Irccd.Plugin/index.md --- a/doc/html/api/module/Irccd.Plugin/index.md Thu Jul 27 16:44:57 2017 +0200 +++ b/doc/html/api/module/Irccd.Plugin/index.md Thu Jul 20 15:12:41 2017 +0200 @@ -8,22 +8,17 @@ This module let you manage plugins. -## Constants +## Objects -The following properties are defined: +The following properties are defined as read in the configuration file: - - **cachePath**: (string) the path to the cache directory, - - **configPath**: (string) the path to the configuration directory, - - **dataPath**: (string) the path to the data directory. - -## Configuration - -An additional property `config` is defined with all options set in the appropriate `[plugin.]` from the user -configuration file. + - **config**: the `[plugin.]` section, + - **paths**: the `[paths.]` section, + - **format**: the `[format.]` section. ### Example -If the configuration file configures the plugin **xyz**: +Assuming the configuration file is defined as following:
~/.config/irccd/irccd.conf
@@ -32,15 +27,24 @@ [plugin.xyz] foo = true baz = "hello" + +[paths.xyz] +config = "/etc/xyz" ````
-Then `Irccd.Plugin.config` will have the following properties: +The `Irccd.Plugin.config` will have the following properties: - **foo**: (string) set to "true", - **baz**: (string) set to "hello". +The `Irccd.Plugin.paths` will have the following properties: + + - **cache**: (string) set to the default cache directory, + - **config**: (string) set to "/etc/xyz", + - **data**: (string) set to the default data directory. + ## Functions - [info](Irccd.Plugin.info.html) diff -r daf3aa8b2ddb -r 0b156b82b8c1 doc/html/irccd/configuring.md --- a/doc/html/irccd/configuring.md Thu Jul 27 16:44:57 2017 +0200 +++ b/doc/html/irccd/configuring.md Thu Jul 20 15:12:41 2017 +0200 @@ -164,6 +164,46 @@ channels = ( "#staff", "#club:secret" ) ```` +# The paths section + +The paths section defines common paths used as defaults for all plugins. + +Any option in this section can be defined altough the following are used as +common convention used in all plugins: + + - **cache**: (string) path for data files written by the plugin, + - **data**: (string) path for data files provided by the user, + - **config**: (string) path for additional configuration from the user. + +For each of these paths, **plugin/name** is appended with the appropriate +plugin name when loaded. + +The section is redefinable per plugin basis using the `[paths.]` syntax. + +**Example** + +````ini +# +# Common for all plugins. +# +# Example with ask plugin: +# +# cache -> /var/cache/irccd/plugin/ask +# config -> /usr/local/etc/irccd/plugin/ask +# data -> /var/data/irccd/plugin/ask +# +[paths] +cache = "/var/cache/irccd" +config = "/usr/local/etc/irccd" +data = "/var/data/irccd" + +# +# Explicit override for plugin hangman. +# +[paths.hangman] +config = "/etc/hangman" +```` + # The plugins section This section is used to load plugins. diff -r daf3aa8b2ddb -r 0b156b82b8c1 doc/html/irccd/paths.md --- a/doc/html/irccd/paths.md Thu Jul 27 16:44:57 2017 +0200 +++ b/doc/html/irccd/paths.md Thu Jul 20 15:12:41 2017 +0200 @@ -6,7 +6,6 @@ Irccd uses different types of paths depending on the context. - Configuration - - Data - Plugins Paths prefixed by (W) means they are only used on Windows, others prefixed by @@ -30,38 +29,6 @@ - `C:/Program Files/irccd/etc/irccd.conf` - `C:/Users/john/AppData/irccd/config` -# Data - -The data directory is only used by plugins, it is dedicated to store important -files such as plugin assets, logs or anything that is meaningful for the user -or the plugin. - - - -The following directories as searched in order: - - - \(W) `%APPDATA%/irccd/share` - - \(U) `${XDG_DATA_HOME}/irccd` - - \(U) `${HOME}/.local/share/irccd` (if `XDG_DATA_HOME` is not set) - - \(W) `installation-directory/share` - - \(U) `installation-directory/share/irccd` - -For plugins, the path is appended with `plugin/` (e.g. plugin/ask). - -Examples: - - - `/home/john/.local/share/irccd/plugin/ask` - - `/usr/local/share/irccd/plugin/ask` - - `C:/Users/john/AppData/irccd/share/plugin/ask` - - `C:/Program Files/irccd/share/plugin/ask` - # Plugins These directories are searched in the following order to load plugins when they diff -r daf3aa8b2ddb -r 0b156b82b8c1 irccd/main.cpp --- a/irccd/main.cpp Thu Jul 27 16:44:57 2017 +0200 +++ b/irccd/main.cpp Thu Jul 20 15:12:41 2017 +0200 @@ -38,7 +38,6 @@ #include "command.hpp" #include "logger.hpp" #include "options.hpp" -#include "path.hpp" #include "service.hpp" #include "system.hpp" #include "config.hpp" @@ -111,7 +110,6 @@ { // Needed for some components. sys::setProgramName("irccd"); - path::setApplicationPath(argv[0]); // Default logging to console. log::setVerbose(false); diff -r daf3aa8b2ddb -r 0b156b82b8c1 irccdctl/main.cpp --- a/irccdctl/main.cpp Thu Jul 27 16:44:57 2017 +0200 +++ b/irccdctl/main.cpp Thu Jul 20 15:12:41 2017 +0200 @@ -31,7 +31,6 @@ #include "irccdctl.hpp" #include "logger.hpp" #include "options.hpp" -#include "path.hpp" #include "system.hpp" #include "util.hpp" @@ -560,9 +559,8 @@ if (it != result.end() || (it = result.find("--config")) != result.end()) read(it->second); else { - for (const std::string &dir : path::list(path::PathConfig)) { + for (const auto& path : sys::config_filenames("irccdctl.conf")) { boost::system::error_code ec; - std::string path = dir + "irccdctl.conf"; if (boost::filesystem::exists(path, ec) && !ec) { read(path); diff -r daf3aa8b2ddb -r 0b156b82b8c1 libcommon/CMakeLists.txt --- a/libcommon/CMakeLists.txt Thu Jul 27 16:44:57 2017 +0200 +++ b/libcommon/CMakeLists.txt Thu Jul 20 15:12:41 2017 +0200 @@ -28,7 +28,6 @@ ${libcommon_SOURCE_DIR}/irccd/logger.hpp ${libcommon_SOURCE_DIR}/irccd/net.hpp ${libcommon_SOURCE_DIR}/irccd/options.hpp - ${libcommon_SOURCE_DIR}/irccd/path.hpp ${libcommon_SOURCE_DIR}/irccd/signals.hpp ${libcommon_SOURCE_DIR}/irccd/system.hpp ${libcommon_SOURCE_DIR}/irccd/util.hpp @@ -42,7 +41,6 @@ ${libcommon_SOURCE_DIR}/irccd/ini.cpp ${libcommon_SOURCE_DIR}/irccd/logger.cpp ${libcommon_SOURCE_DIR}/irccd/options.cpp - ${libcommon_SOURCE_DIR}/irccd/path.cpp ${libcommon_SOURCE_DIR}/irccd/system.cpp ${libcommon_SOURCE_DIR}/irccd/util.cpp ) diff -r daf3aa8b2ddb -r 0b156b82b8c1 libcommon/irccd/path.cpp --- a/libcommon/irccd/path.cpp Thu Jul 27 16:44:57 2017 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,546 +0,0 @@ -/* - * path.cpp -- special paths inside irccd - * - * Copyright (c) 2013-2017 David Demelier - * - * 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 -#include -#include -#include - -#include - -#include "sysconfig.hpp" - -#if defined(IRCCD_SYSTEM_WINDOWS) -# include -# include -#else -# if defined(IRCCD_SYSTEM_LINUX) -# include -# include -# include -# include -# include -# endif - -# if defined(IRCCD_SYSTEM_FREEBSD) -# include -# include -# include - -# include -# include -# include -# include -# endif - -# if defined(IRCCD_SYSTEM_MAC) -# include -# include -# include -# include -# endif - -# include "xdg.hpp" -#endif - -#include "fs.hpp" -#include "path.hpp" -#include "system.hpp" -#include "util.hpp" - -namespace irccd { - -namespace path { - -namespace { - -/* - * Base program directory - * ------------------------------------------------------------------ - * - * This variable stores the program base directory. - * - * If it is empty, the program was not able to detect it (e.g. error, not - * supported). - */ - -std::string base{"."}; - -/* - * executablePath. - * ------------------------------------------------------------------ - * - * Get the executable directory. - */ - -#if defined(IRCCD_SYSTEM_WINDOWS) - -std::string executablePath() -{ - std::string result; - std::size_t size = MAX_PATH; - - result.resize(size); - - if (!(size = GetModuleFileNameA(nullptr, &result[0], size))) - throw std::runtime_error("GetModuleFileName error"); - - result.resize(size); - - return result; -} - -#elif defined(IRCCD_SYSTEM_LINUX) - -std::string executablePath() -{ - std::string result; - - result.resize(2048); - - auto size = readlink("/proc/self/exe", &result[0], 2048); - - if (size < 0) - throw std::invalid_argument(std::strerror(errno)); - - result.resize(size); - - return result; -} - -#elif defined(IRCCD_SYSTEM_FREEBSD) - -std::string executablePath() -{ - std::array mib{ { CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1 } }; - std::string result; - std::size_t size = PATH_MAX + 1; - - result.resize(size); - - if (sysctl(mib.data(), 4, &result[0], &size, nullptr, 0) < 0) - throw std::runtime_error(std::strerror(errno)); - - result.resize(size); - - return result; -} - -#elif defined(IRCCD_SYSTEM_MAC) - -std::string executablePath() -{ - std::string result; - std::size_t size = PROC_PIDPATHINFO_MAXSIZE; - - result.resize(size); - - if ((size = proc_pidpath(getpid(), &result[0], size)) == 0) - throw std::runtime_error(std::strerror(errno)); - - result.resize(size); - - return result; -} - -#else - -/* - * TODO: add support for more systems here. - * - * - NetBSD - * - OpenBSD - */ - -std::string executablePath() -{ - return ""; -} - -#endif - -/* - * System paths. - * ------------------------------------------------------------------ - * - * Compute system paths. - * - * Do not call any of these functions if irccd is relocatable and base is unset. - */ - -std::string systemConfig() -{ - return base + WITH_CONFDIR; -} - -std::string systemData() -{ - return base + WITH_DATADIR; -} - -std::string systemCache() -{ - return base + WITH_CACHEDIR; -} - -std::string systemPlugins() -{ - return base + WITH_PLUGINDIR; -} - -std::string systemNativePlugins() -{ - return base + WITH_NPLUGINDIR; -} - -/* - * User paths. - * ------------------------------------------------------------------ - * - * Compute user paths. - */ - -/* - * userConfig. - * --------------------------------------------------------- - * - * Get the path directory to the user configuration. Example: - * - * Unix: - * - * XDG_CONFIG_HOME/irccd - * HOME/.config/irccd - * - * Windows: - * - * CSIDL_LOCAL_APPDATA/irccd/config - */ -std::string userConfig() -{ - std::ostringstream oss; - -#if defined(IRCCD_SYSTEM_WINDOWS) - char path[MAX_PATH]; - - if (SHGetFolderPathA(nullptr, CSIDL_LOCAL_APPDATA, nullptr, 0, path) != S_OK) - oss << ""; - else { - oss << path; - oss << "\\irccd\\config\\"; - } -#else - try { - Xdg xdg; - - oss << xdg.configHome(); - oss << "/irccd/"; - } catch (const std::exception &) { - const char *home = getenv("HOME"); - - if (home != nullptr) - oss << home; - - oss << "/.config/irccd/"; - } -#endif - - return oss.str(); -} - -/* - * userData. - * -------------------------------------------------------- - * - * Get the path to the data application. - * - * Unix: - * - * XDG_DATA_HOME/irccd - * HOME/.local/share/irccd - * - * Windows: - * - * CSIDL_LOCAL_APPDATA - */ -std::string userData() -{ - std::ostringstream oss; - -#if defined(IRCCD_SYSTEM_WINDOWS) - char path[MAX_PATH]; - - if (SHGetFolderPathA(nullptr, CSIDL_LOCAL_APPDATA, nullptr, 0, path) != S_OK) - oss << ""; - else { - oss << path; - oss << "\\irccd\\share"; - } -#else - try { - Xdg xdg; - - oss << xdg.dataHome(); - oss << "/irccd/"; - } catch (const std::exception &) { - const char *home = getenv("HOME"); - - if (home != nullptr) - oss << home; - - oss << "/.local/share/irccd/"; - } -#endif - - return oss.str(); -} - -/* - * userCache. - * -------------------------------------------------------- - * - * Directory for cache files. - * - * Unix: - * - * XDG_CACHE_HOME/irccd - * HOME/.cache/irccd - * - * Windows: - * - * %TEMP% (e.g. C:\Users\\AppData\Local\Temp) - */ -std::string userCache() -{ - std::ostringstream oss; - -#if defined(IRCCD_SYSTEM_WINDOWS) - char path[MAX_PATH + 1]; - - GetTempPathA(sizeof (path), path); - - oss << path << "\\irccd\\"; -#else - try { - Xdg xdg; - - oss << xdg.cacheHome(); - oss << "/irccd/"; - } catch (const std::exception &) { - const char *home = getenv("HOME"); - - if (home != nullptr) - oss << home; - - oss << "/.cache/irccd/"; - } -#endif - - return oss.str(); -} - -/* - * userPlugins. - * -------------------------------------------------------- - * - * Path to the data + plugins. - */ -std::string userPlugins() -{ - return userData() + "/plugins/"; -} - -} // !namespace - -#if defined(IRCCD_SYSTEM_WINDOWS) -const char Separator(';'); -#else -const char Separator(':'); -#endif - -void setApplicationPath(const std::string &argv0) -{ - try { - base = executablePath(); - } catch (const std::exception &) { - /* - * If an exception is thrown, that means the operating system supports a - * function to get the executable path but it failed. - * - * TODO: show a waning - */ - } - - /* - * If we could not get the application path from the native function, check - * if argv[0] is an absolute path and use that from there. - * - * Otherwise, search from the PATH. - * - * In the worst case use current working directory. - */ - if (base.empty()) { - if (boost::filesystem::path(argv0).is_absolute()) { - base = argv0; - } else { - std::string name = fs::baseName(argv0); - - for (const auto &dir : util::split(sys::env("PATH"), std::string(1, Separator))) { - boost::system::error_code ec; - std::string path = dir + fs::separator() + name; - - if (boost::filesystem::exists(path, ec) && !ec) { - base = path; - break; - } - } - - // Not found in PATH? add dummy value. - if (base.empty()) - base = std::string(".") + fs::separator() + WITH_BINDIR + fs::separator() + "dummy"; - } - } - - // Find bin/. - auto pos = base.rfind(std::string(WITH_BINDIR) + fs::separator() + fs::baseName(base)); - - if (pos != std::string::npos) - base.erase(pos); - - // Add trailing / or \\ for convenience. - base = clean(base); - - assert(!base.empty()); -} - -std::string clean(std::string input) -{ - if (input.empty()) - return input; - - // First, remove any duplicates. - input.erase(std::unique(input.begin(), input.end(), [&] (char c1, char c2) { - return c1 == c2 && (c1 == '/' || c1 == '\\'); - }), input.end()); - - // Add a trailing / or \\. - char c = input[input.length() - 1]; - if (c != '/' && c != '\\') - input += fs::separator(); - - // Now converts all / to \\ for Windows and the opposite for Unix. -#if defined(IRCCD_SYSTEM_WINDOWS) - std::replace(input.begin(), input.end(), '/', '\\'); -#else - std::replace(input.begin(), input.end(), '\\', '/'); -#endif - - return input; -} - -std::string get(Path path, Owner owner) -{ - assert(path >= PathConfig && path <= PathNativePlugins); - assert(owner >= OwnerSystem && owner <= OwnerUser); - - std::string result; - - switch (owner) { - case OwnerSystem: - switch (path) { - case PathCache: - result = clean(systemCache()); - break; - case PathConfig: - result = clean(systemConfig()); - break; - case PathData: - result = clean(systemData()); - break; - case PathPlugins: - result = clean(systemPlugins()); - break; - case PathNativePlugins: - result = clean(systemNativePlugins()); - break; - default: - break; - } - case OwnerUser: - switch (path) { - case PathCache: - result = clean(userCache()); - break; - case PathConfig: - result = clean(userConfig()); - break; - case PathData: - result = clean(userData()); - break; - case PathNativePlugins: - case PathPlugins: - result = clean(userPlugins()); - break; - default: - break; - } - default: - break; - } - - return result; -} - -std::vector list(Path path) -{ - assert(path >= PathConfig && path <= PathNativePlugins); - - std::vector list; - boost::system::error_code ec; - - switch (path) { - case PathCache: - list.push_back(clean(userCache())); - list.push_back(clean(systemCache())); - break; - case PathConfig: - list.push_back(clean(userConfig())); - list.push_back(clean(systemConfig())); - break; - case PathData: - list.push_back(clean(userData())); - list.push_back(clean(systemData())); - break; - case PathPlugins: - list.push_back(clean(boost::filesystem::current_path(ec).string())); - list.push_back(clean(userPlugins())); - list.push_back(clean(systemPlugins())); - break; - case PathNativePlugins: - list.push_back(clean(boost::filesystem::current_path(ec).string())); - list.push_back(clean(systemNativePlugins())); - break; - default: - break; - } - - return list; -} - -} // !path - -} // !irccd diff -r daf3aa8b2ddb -r 0b156b82b8c1 libcommon/irccd/path.hpp --- a/libcommon/irccd/path.hpp Thu Jul 27 16:44:57 2017 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,111 +0,0 @@ -/* - * path.hpp -- special paths inside irccd - * - * Copyright (c) 2013-2017 David Demelier - * - * 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. - */ - -#ifndef IRCCD_PATH_HPP -#define IRCCD_PATH_HPP - -/** - * \file path.hpp - * \brief Path management. - */ - -#include -#include - -#include "sysconfig.hpp" - -namespace irccd { - -/** - * \brief Namespace for paths. - */ -namespace path { - -/** - * brief PATH separator, either : or ;. - */ -extern const char Separator; - -/** - * \enum Path - * \brief Which special path to get - */ -enum Path { - PathConfig, //!< Configuration files - PathData, //!< Data directory - PathCache, //!< Cache files - PathPlugins, //!< Path to the plugins - PathNativePlugins //!< Path to native plugins -}; - -/** - * \enum Owner - * \brief For paths, get the installation path or the user ones - */ -enum Owner { - OwnerSystem, //!< System wide - OwnerUser //!< User -}; - -/** - * This function must be called before at the beginning of the main. - * - * It use system dependant program path lookup if available and fallbacks to the - * path given as argument if any failure was encoutered. - * - * \param argv0 the path to the executable (argv[0]) - */ -IRCCD_EXPORT void setApplicationPath(const std::string &argv0); - -/** - * Clean a path by removing any extra / or \ and add a trailing one. - * - * \param path the path - * \return the updated path - */ -IRCCD_EXPORT std::string clean(std::string path); - -/** - * Generic function for path retrievement. - * - * The path is always terminated by a trailing / or \\. - * - * \pre setApplicationPath must have been called - * \param path the type of path - * \param owner system or user wide - * \return the path - */ -IRCCD_EXPORT std::string get(Path path, Owner owner); - -/** - * Generic function for multiple paths. - * - * This function will add more directories than pathSystem*() and pathUser*() - * functions. - * - * \pre setApplicationPath must have been called - * \param path the type of path - * \return the list of preferred directories in order - */ -IRCCD_EXPORT std::vector list(Path path); - -} // !path - -} // !irccd - -#endif // !IRCCD_PATH_HPP diff -r daf3aa8b2ddb -r 0b156b82b8c1 libcommon/irccd/system.cpp --- a/libcommon/irccd/system.cpp Thu Jul 27 16:44:57 2017 +0200 +++ b/libcommon/irccd/system.cpp Thu Jul 20 15:12:41 2017 +0200 @@ -16,60 +16,93 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include +#include #include #include #include +#include + +#include #include "sysconfig.hpp" #if defined(HAVE_SETPROGNAME) -# include -#endif - -#if defined(IRCCD_SYSTEM_WINDOWS) -# include -# include -# include -# include -#else // All non Windows -#if defined(IRCCD_SYSTEM_MAC) -# include +# include #endif #if defined(IRCCD_SYSTEM_LINUX) -# include +# include + +# include + +# include +# include +# include +#elif defined(IRCCD_SYSTEM_FREEBSD) || + defined(IRCCD_SYSTEM_DRAGONFLYBSD) || + defined(IRCCD_SYSTEM_NETBSD) || + defined(IRCCD_SYSTEM_OPENBSD) +# if defined(IRCCD_SYSTEM_NETBSD) +# include +# else +# include +# endif + +# if defined(IRCCD_SYSTEM_OPENBSD) +# include +# endif + +# include + +# include +# include +# include +# include +# include +#elif defined(IRCCD_SYSTEM_MAC) +# include +# include +# include +# include +# include +#elif defined(IRCCD_SYSTEM_WINDOWS) +# include +# include +# include +# include #endif -# include -# include -# include -# include +#if !defined(IRCCD_SYSTEM_WINDOWS) +# include +# include +# include +# include -# include -# include -# include -# include - +# include +# include +# include #endif // For sys::setGid. #if defined(HAVE_SETGID) -# include -# include -# include +# include +# include +# include #endif // For sys::setUid. #if defined(HAVE_SETGID) -# include -# include -# include +# include +# include +# include #endif #include "fs.hpp" #include "logger.hpp" #include "system.hpp" #include "util.hpp" +#include "xdg.hpp" namespace irccd { @@ -78,6 +111,14 @@ namespace { /* + * XXX: the setprogname() function keeps a pointer without copying it so when + * main's argv is modified, we're not using the same name so create our own + * copy. + */ + +std::string programNameCopy; + +/* * setHelper. * ------------------------------------------------------------------ * @@ -124,12 +165,235 @@ } /* - * XXX: the setprogname() function keeps a pointer without copying it so when - * main's argv is modified, we're not using the same name so create our own - * copy. + * executable_path + * ------------------------------------------------------------------ + * + * Get the executable path. + * + * Example: + * + * /usr/local/bin/irccd -> /usr/local/bin + */ +std::string executable_path() +{ + std::string result; + +#if defined(__linux__) + char path[PATH_MAX + 1] = {0}; + + if (readlink("/proc/self/exe", path, sizeof (path) - 1) < 0) + throw std::runtime_error(std::strerror(errno)); + + result = path; +#elif defined(__FreeBSD__) || defined(__DragonFly__) + int size = PATH_MAX, mib[] = { CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1 }; + char path[PATH_MAX + 1] = {0}; + + if (sysctl(mib, 4, path, &size, nullptr, 0) < 0) + throw std::runtime_error(std::strerror(errno)); + + result = path; +#elif defined(__APPLE__) + char path[PROC_PIDPATHINFO_MAXSIZE + 1] = {0}; + + if ((proc_pidpath(getpid(), path, sizeof (path) - 1) == 0) + throw std::runtime_error(std::strerror(errno)); + + result = path; +#elif defined(_WIN32) + char path[PATH_MAX + 1] = {0}; + + if (GetModuleFileNameA(nullptr, path, sizeof (path) - 1) == 0) + throw std::runtime_error("GetModuleFileName error"); + + result = path; +#elif defined(__NetBSD__) + char path[4096 + 1] = {0}; + +# if defined(KERN_PROC_PATHNAME) + int mib[] = { CTL_KERN, KERN_PROC_ARGS, -1, KERN_PROC_PATHNAME }; + int size = sizeof (path) - 1; + + if (sysctl(mib, 4, path, &size, nullptr, 0) < 0) + throw std::runtime_error(std::strerror(errno)); +# else + if (readlink("/proc/curproc/exe", path, sizeof (path) - 1) < 0) + throw std::runtime_error(std::strerror(errno)); +# endif + + result = path; +#elif defined(__OpenBSD__) + char **paths, path[PATH_MAX + 1] = {0}; + int length, mib[] = { CTL_KERN, KERN_PROC_ARGS, getpid(), KERN_PROC_ARGV }; + + if (sysctl(mib, 4, nullptr, &length, nullptr, 0) < 0) + throw std::runtime_error(std::strerror(errno)); + if ((paths = static_cast(std::malloc(length))) == nullptr) + throw std::runtime_error(std::strerror(errno)); + if (sysctl(mib, 4, paths, &length, nullptr, 0) < 0) { + std::free(paths); + throw std::runtime_error(std::strerror(errno)); + } + + realpath(paths[0], path); + result = path; + + std::free(paths); + std::free(path); +#endif + return result; +} + +/* + * add_config_user_path + * ------------------------------------------------------------------ + * + * Referenced by: config_filenames. + * + * Add user config path. */ +void add_config_user_path(std::vector& result, const std::string& file) +{ + boost::filesystem::path path; -std::string programNameCopy; +#if defined(IRCCD_SYSTEM_WINDOWS) + char folder[MAX_PATH] = {0}; + + if (SHGetFolderPathA(nullptr, CSIDL_LOCAL_APPDATA, nullptr, 0, folder) == S_OK) + path = folder + "\\irccd\\config"; + else + path = "."; +#else + try { + path = Xdg().configHome(); + } catch (...) { + path = sys::env("HOME"); + path /= ".config"; + } + + path /= "irccd"; +#endif + + path /= file; + result.push_back(path.string()); +} + +/* + * add_plugin_user_path + * ------------------------------------------------------------------ + * + * Referenced by: plugin_filenames. + * + * Like add add_config_user_path but for plugins. + */ +void add_plugin_user_path(std::vector& result, const std::string& file) +{ + boost::filesystem::path path; + +#if defined(IRCCD_SYSTEM_WINDOWS) + char folder[MAX_PATH] = {0}; + + if (SHGetFolderPathA(nullptr, CSIDL_LOCAL_APPDATA, nullptr, 0, folder) == S_OK) + path = folder + "\\irccd\\share"; +#else + try { + path = Xdg().dataHome(); + } catch (...) { + path = sys::env("HOME"); + path /= ".local/share"; + } + + path /= "irccd"; +#endif + + path /= file; + result.push_back(path.string()); +} + +/* + * base_directory + * ------------------------------------------------------------------ + * + * Get the base program directory. + * + * If irccd has been compiled with relative paths, the base directory is + * evaluated by climbing the `bindir' directory from the executable path. + * + * Otherwise, use the installation prefix. + */ +boost::filesystem::path base_directory() +{ + static const boost::filesystem::path bindir(WITH_BINDIR); + static const boost::filesystem::path prefix(PREFIX); + + boost::filesystem::path path("."); + + if (bindir.is_relative()) { + try { + path = executable_path(); + path = path.parent_path(); + } catch (...) { + path = "./"; + } + + // Compute relative base directory. + for (auto len = std::distance(bindir.begin(), bindir.end()); len > 0; len--) + path = path.parent_path(); + if (path.empty()) + path = "."; + } else + path = prefix; + + return path; +} + +/* + * add_system_path + * ------------------------------------------------------------------ + * + * Referenced by: config_filenames, + * plugin_filenames + * + * Add system path into the result list. + */ +void add_system_path(std::vector& result, + const std::string& file, + const boost::filesystem::path& component) +{ + boost::filesystem::path path; + + if (component.is_absolute()) + path = component; + else { + path = base_directory(); + path /= component; + } + + path /= file; + result.push_back(path.string()); +} + +/* + * system_directory + * ------------------------------------------------------------------ + * + * Compute the system wise directory path for the given component. + * + * Referenced by: cachedir, + * datadir, + * sysconfigdir + */ +std::string system_directory(const std::string& component) +{ + boost::filesystem::path path(component); + + if (path.is_relative()) { + path = base_directory(); + path /= component; + } + + return path.string(); +} } // !namespace @@ -155,6 +419,8 @@ return "Windows"; #elif defined(IRCCD_SYSTEM_FREEBSD) return "FreeBSD"; +#elif defined(IRCCD_SYSTEM_DRAGONFLYBSD) + return "DragonFlyBSD"; #elif defined(IRCCD_SYSTEM_OPENBSD) return "OpenBSD"; #elif defined(IRCCD_SYSTEM_NETBSD) @@ -279,6 +545,46 @@ #endif +std::string cachedir() +{ + return system_directory(WITH_CACHEDIR); +} + +std::string datadir() +{ + return system_directory(WITH_DATADIR); +} + +std::string sysconfigdir() +{ + return system_directory(WITH_SYSCONFDIR); +} + +std::vector config_filenames(std::string file) +{ + std::vector result; + + add_config_user_path(result, file); + add_system_path(result, file, WITH_SYSCONFDIR); + + return result; +} + +std::vector plugin_filenames(const std::string& name, + const std::vector& extensions) +{ + assert(!extensions.empty()); + + std::vector result; + + for (const auto& ext : extensions) + add_plugin_user_path(result, name + ext); + for (const auto& ext : extensions) + add_system_path(result, name + ext, WITH_PLUGINDIR); + + return result; +} + } // !sys } // !irccd diff -r daf3aa8b2ddb -r 0b156b82b8c1 libcommon/irccd/system.hpp --- a/libcommon/irccd/system.hpp Thu Jul 27 16:44:57 2017 +0200 +++ b/libcommon/irccd/system.hpp Thu Jul 20 15:12:41 2017 +0200 @@ -26,6 +26,9 @@ #include #include +#include + +#include #include "sysconfig.hpp" @@ -115,6 +118,61 @@ #endif +/** + * Get the cache directory as specified as compile time option WITH_CACHEDIR, if + * the value is absolute, it is returned as-is. + * + * If the component is relative, it is evaluated using the binary executable + * path. + * + * \return the evaluated cache directory. + * \see datadir + * \see configdir + */ +std::string cachedir(); + +/** + * Like cachedir but for WITH_DATADIR. + * + * \return the evaluated data directory. + * \see cachedir + * \see datadir + */ +std::string datadir(); + +/** + * Like cachedir but for WITH_SYSCONFIGDIR. + * + * \return the evaluated config directory. + * \see cachedir + * \see datadir + * \note use config_filenames for irccd.conf, irccdctl.conf files + */ +std::string sysconfigdir(); + + +/** + * Construct a list of paths to read configuration files from. + * + * This function does not test the presence of the files as a condition race + * may occur. + * + * The caller is responsible of opening files for each path. + * + * \param file the filename to append for convenience + * \return the list of paths to check in order + */ +std::vector config_filenames(std::string file); + +/** + * Construct a list of paths for reading plugins. + * + * \param name the plugin id (without extension) + * \param extensions the list of extensions supported + */ +std::vector plugin_filenames(const std::string& name, + const std::vector& extensions); + } // !sys } // !irccd diff -r daf3aa8b2ddb -r 0b156b82b8c1 libirccd-js/irccd/mod-directory.cpp --- a/libirccd-js/irccd/mod-directory.cpp Thu Jul 27 16:44:57 2017 +0200 +++ b/libirccd-js/irccd/mod-directory.cpp Thu Jul 20 15:12:41 2017 +0200 @@ -30,7 +30,6 @@ #include "fs.hpp" #include "mod-directory.hpp" #include "mod-irccd.hpp" -#include "path.hpp" #include "plugin-js.hpp" #include "sysconfig.hpp" @@ -129,8 +128,6 @@ */ duk_ret_t find(duk_context *ctx, std::string base, bool recursive, int patternIndex) { - base = path::clean(base); - try { std::string path; diff -r daf3aa8b2ddb -r 0b156b82b8c1 libirccd-js/irccd/mod-plugin.cpp --- a/libirccd-js/irccd/mod-plugin.cpp Thu Jul 27 16:44:57 2017 +0200 +++ b/libirccd-js/irccd/mod-plugin.cpp Thu Jul 20 15:12:41 2017 +0200 @@ -112,7 +112,7 @@ * get * ------------------------------------------------------------------ * - * Get the Irccd.plugin->(config|format) property. + * Get the Irccd.plugin->(config|format|paths) property. */ duk_ret_t get(duk_context *ctx, const char *name) { @@ -166,7 +166,29 @@ } /* - * Function: Irccd.plugin->info([name]) + * setPaths + * ------------------------------------------------------------------ + * + * Wrap setter for Irccd.plugin->format property. + */ +duk_ret_t setPaths(duk_context *ctx) +{ + return set(ctx, JsPlugin::PathsProperty); +} + +/* + * getPaths + * ------------------------------------------------------------------ + * + * Wrap getter for Irccd.plugin->format property. + */ +duk_ret_t getPaths(duk_context *ctx) +{ + return get(ctx, JsPlugin::PathsProperty); +} + +/* + * Function: Irccd.plugin.info([name]) * ------------------------------------------------------------------ * * Get information about a plugin-> @@ -337,6 +359,12 @@ duk_push_c_function(plugin->context(), setFormat, 1); duk_def_prop(plugin->context(), -4, DUK_DEFPROP_HAVE_GETTER | DUK_DEFPROP_HAVE_SETTER); + // 'format' property. + duk_push_string(plugin->context(), "paths"); + duk_push_c_function(plugin->context(), getPaths, 0); + duk_push_c_function(plugin->context(), setPaths, 1); + duk_def_prop(plugin->context(), -4, DUK_DEFPROP_HAVE_GETTER | DUK_DEFPROP_HAVE_SETTER); + duk_put_prop_string(plugin->context(), -2, "Plugin"); duk_pop(plugin->context()); } diff -r daf3aa8b2ddb -r 0b156b82b8c1 libirccd-js/irccd/plugin-js.cpp --- a/libirccd-js/irccd/plugin-js.cpp Thu Jul 27 16:44:57 2017 +0200 +++ b/libirccd-js/irccd/plugin-js.cpp Thu Jul 20 15:12:41 2017 +0200 @@ -39,6 +39,7 @@ const char JsPlugin::ConfigProperty[] = "\xff""\xff""irccd-plugin-config"; const char JsPlugin::FormatProperty[] = "\xff""\xff""irccd-plugin-format"; +const char JsPlugin::PathsProperty[] = "\xff""\xff""irccd-plugin-paths"; std::unordered_map JsPlugin::getTable(const char *name) const { @@ -98,35 +99,6 @@ duk_put_global_string(m_context, "\xff""\xff""path"); } -void JsPlugin::putPath(const std::string &varname, const std::string &append, path::Path type) -{ - StackAssert sa(m_context); - - bool found = true; - std::string foundpath; - - // Use the first existing directory available. - for (const auto &p : path::list(type)) { - boost::system::error_code ec; - foundpath = path::clean(p + append); - - if (boost::filesystem::exists(foundpath, ec) && !ec) { - found = true; - break; - } - } - - // Use the system as default. - if (!found) - foundpath = path::clean(path::get(type, path::OwnerSystem) + append); - - duk_get_global_string(m_context, "Irccd"); - duk_get_prop_string(m_context, -1, "Plugin"); - dukx_push_std_string(m_context, foundpath); - duk_put_prop_string(m_context, -2, varname.c_str()); - duk_pop_2(m_context); -} - JsPlugin::JsPlugin(std::string name, std::string path) : Plugin(name, path) { @@ -136,6 +108,7 @@ * * - Irccd.Plugin.config * - Irccd.Plugin.format + * - Irccd.Plugin.paths * * In mod-plugin.cpp. */ @@ -143,6 +116,8 @@ duk_put_global_string(m_context, ConfigProperty); duk_push_object(m_context); duk_put_global_string(m_context, FormatProperty); + duk_push_object(m_context); + duk_put_global_string(m_context, PathsProperty); // Used by many Javascript APIs. duk_push_object(m_context); @@ -238,15 +213,6 @@ throw std::runtime_error(std::strerror(errno)); #endif - /* - * dataPath: DATA + plugin/name (e.g ~/.local/share/irccd/plugins//) - * configPath: CONFIG + plugin/name (e.g ~/.config/irccd/plugin//) - */ - putVars(); - putPath("dataPath", "plugin/" + name(), path::PathData); - putPath("configPath", "plugin/" + name(), path::PathConfig); - putPath("cachePath", "plugin/" + name(), path::PathCache); - // Try to load the file (does not call onLoad yet). dukx_peval_file(m_context, path()); duk_pop(m_context); @@ -256,8 +222,10 @@ * calling onLoad to allow the plugin adding configuration to * Irccd.Plugin.(config|format) before the user. */ + putVars(); setConfig(irccd.plugins().config(name())); setFormats(irccd.plugins().formats(name())); + setPaths(irccd.plugins().paths(name())); // Read metadata . duk_get_global_string(m_context, "info"); @@ -426,7 +394,8 @@ } JsPluginLoader::JsPluginLoader(Irccd &irccd) noexcept - : m_irccd(irccd) + : PluginLoader({}, { ".js" }) + , m_irccd(irccd) { } @@ -462,20 +431,4 @@ return nullptr; } -std::shared_ptr JsPluginLoader::find(const std::string &id) noexcept -{ - for (const auto &dir : path::list(path::PathPlugins)) { - auto path = dir + id + ".js"; - - if (!fs::isReadable(path)) - continue; - - log::info() << "plugin " << id << ": trying " << path << std::endl; - - return open(id, path); - } - - return nullptr; -} - } // !irccd diff -r daf3aa8b2ddb -r 0b156b82b8c1 libirccd-js/irccd/plugin-js.hpp --- a/libirccd-js/irccd/plugin-js.hpp Thu Jul 27 16:44:57 2017 +0200 +++ b/libirccd-js/irccd/plugin-js.hpp Thu Jul 20 15:12:41 2017 +0200 @@ -27,7 +27,6 @@ #include #include "duktape.hpp" -#include "path.hpp" #include "plugin.hpp" namespace irccd { @@ -50,6 +49,11 @@ */ static const char FormatProperty[]; + /** + * Global property where paths are defined (object). + */ + static const char PathsProperty[]; + private: // JavaScript context UniqueContext m_context; @@ -59,7 +63,6 @@ void putTable(const char *name, const std::unordered_map &vars); void call(const std::string &name, unsigned nargs = 0); void putVars(); - void putPath(const std::string &varname, const std::string &append, path::Path type); public: /** @@ -113,6 +116,22 @@ } /** + * \copydoc Plugin::paths + */ + PluginPaths paths() override + { + return getTable(PathsProperty); + } + + /** + * \copydoc Plugin::set_paths + */ + void setPaths(PluginPaths paths) override + { + putTable(PathsProperty, std::move(paths)); + } + + /** * \copydoc Plugin::onCommand */ IRCCD_EXPORT void onCommand(Irccd &irccd, const MessageEvent &event) override; @@ -238,11 +257,6 @@ */ std::shared_ptr open(const std::string &id, const std::string &path) noexcept override; - - /** - * \copydoc PluginLoader::find - */ - std::shared_ptr find(const std::string &id) noexcept override; }; } // !irccd diff -r daf3aa8b2ddb -r 0b156b82b8c1 libirccd/CMakeLists.txt --- a/libirccd/CMakeLists.txt Thu Jul 27 16:44:57 2017 +0200 +++ b/libirccd/CMakeLists.txt Thu Jul 20 15:12:41 2017 +0200 @@ -37,6 +37,7 @@ ${libirccd_SOURCE_DIR}/irccd/command.cpp ${libirccd_SOURCE_DIR}/irccd/config.cpp ${libirccd_SOURCE_DIR}/irccd/irccd.cpp + ${libirccd_SOURCE_DIR}/irccd/plugin.cpp ${libirccd_SOURCE_DIR}/irccd/plugin-dynlib.cpp ${libirccd_SOURCE_DIR}/irccd/rule.cpp ${libirccd_SOURCE_DIR}/irccd/server.cpp diff -r daf3aa8b2ddb -r 0b156b82b8c1 libirccd/irccd/config.cpp --- a/libirccd/irccd/config.cpp Thu Jul 27 16:44:57 2017 +0200 +++ b/libirccd/irccd/config.cpp Thu Jul 20 15:12:41 2017 +0200 @@ -18,18 +18,20 @@ #include +#include + #include #include "config.hpp" #include "fs.hpp" #include "irccd.hpp" #include "logger.hpp" -#include "path.hpp" #include "plugin.hpp" #include "rule.hpp" #include "server.hpp" #include "service.hpp" #include "sysconfig.hpp" +#include "system.hpp" #include "transport.hpp" #include "util.hpp" @@ -100,6 +102,16 @@ return config; } +PluginPaths readPaths(const ini::Section& sc) +{ + PluginPaths paths; + + for (const auto& opt : sc) + paths.emplace(opt.key(), opt.value()); + + return paths; +} + std::unique_ptr loadLogFile(const ini::Section &sc) { /* @@ -374,16 +386,14 @@ Config Config::find() { - for (const auto &path : path::list(path::PathConfig)) { - std::string fullpath = path + "irccd.conf"; + for (const auto& path : sys::config_filenames("irccd.conf")) { + try { + boost::system::error_code ec; - if (!fs::isReadable(fullpath)) - continue; - - try { - return Config(fullpath); + if (boost::filesystem::exists(path, ec) && !ec) + return Config(path); } catch (const std::exception &ex) { - throw std::runtime_error("{}: {}"_format(fullpath, ex.what())); + log::warning() << path << ": " << ex.what() << std::endl; } } @@ -449,6 +459,18 @@ return formats; } +PluginPaths Config::findPluginPaths(const std::string& name) const +{ + assert(util::isIdentifierValid(name)); + + auto section = m_document.find(std::string("paths.") + name); + + if (section == m_document.end()) + return PluginPaths(); + + return readPaths(*section); +} + bool Config::isVerbose() const noexcept { return util::isBoolean(get(m_document, "logs", "verbose")); @@ -559,15 +581,32 @@ return servers; } +PluginPaths Config::loadPaths() const +{ + auto section = m_document.find("paths"); + + if (section == m_document.end()) + return {}; + + return readPaths(*section); +} + void Config::loadPlugins(Irccd &irccd) const { auto it = m_document.find("plugins"); + irccd.plugins().setPaths(loadPaths()); + if (it != m_document.end()) { for (const auto &option : *it) { if (!util::isIdentifierValid(option.key())) continue; + auto paths = findPluginPaths(option.key()); + + if (!paths.empty()) + irccd.plugins().setPaths(std::move(paths)); + irccd.plugins().setConfig(option.key(), findPluginConfig(option.key())); irccd.plugins().setFormats(option.key(), findPluginFormats(option.key())); irccd.plugins().load(option.key(), option.value()); diff -r daf3aa8b2ddb -r 0b156b82b8c1 libirccd/irccd/config.hpp --- a/libirccd/irccd/config.hpp Thu Jul 27 16:44:57 2017 +0200 +++ b/libirccd/irccd/config.hpp Thu Jul 20 15:12:41 2017 +0200 @@ -104,6 +104,14 @@ IRCCD_EXPORT PluginFormats findPluginFormats(const std::string &name) const; /** + * Find plugin paths if defined. + * + * \pre util::isValidIdentifier(name) + * \param name the plugin name + */ + IRCCD_EXPORT PluginPaths findPluginPaths(const std::string& name) const; + + /** * Get the path to the pidfile. * * \return the path or empty if not defined @@ -170,6 +178,13 @@ IRCCD_EXPORT std::vector> loadServers() const; /** + * Load default paths for plugins. + * + * \return the map of paths + */ + IRCCD_EXPORT PluginPaths loadPaths() const; + + /** * Get the list of defined plugins. * * \param irccd the irccd instance diff -r daf3aa8b2ddb -r 0b156b82b8c1 libirccd/irccd/plugin-dynlib.cpp --- a/libirccd/irccd/plugin-dynlib.cpp Thu Jul 27 16:44:57 2017 +0200 +++ b/libirccd/irccd/plugin-dynlib.cpp Thu Jul 20 15:12:41 2017 +0200 @@ -18,7 +18,6 @@ #include "fs.hpp" #include "logger.hpp" -#include "path.hpp" #include "plugin-dynlib.hpp" namespace irccd { @@ -176,34 +175,16 @@ call(m_onWhois, irccd, ev); } -std::shared_ptr DynlibPluginLoader::open(const std::string &id, - const std::string &path) noexcept +std::shared_ptr DynlibPluginLoader::open(const std::string &, + const std::string &) noexcept { - if (path.rfind(DYNLIB_SUFFIX) == std::string::npos) - return nullptr; - - try { - return std::make_shared(id, path); - } catch (const std::exception &ex) { - log::warning() << "plugin " << id << ": " << ex.what() << std::endl; - } - + // TODO: dynlib plugins are unsupported for now. return nullptr; } -std::shared_ptr DynlibPluginLoader::find(const std::string &id) noexcept +std::shared_ptr DynlibPluginLoader::find(const std::string &) noexcept { - for (const auto &dir : path::list(path::PathNativePlugins)) { - auto path = dir + id + DYNLIB_SUFFIX; - - if (!fs::isReadable(path)) - continue; - - log::info() << "plugin " << id << ": trying " << path << std::endl; - - return open(id, path); - } - + // TODO: dynlib plugins are unsupported for now. return nullptr; } diff -r daf3aa8b2ddb -r 0b156b82b8c1 libirccd/irccd/plugin.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libirccd/irccd/plugin.cpp Thu Jul 20 15:12:41 2017 +0200 @@ -0,0 +1,71 @@ +/* + * plugin.cpp -- irccd JavaScript plugin interface + * + * Copyright (c) 2013-2017 David Demelier + * + * 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 + +#include "plugin.hpp" +#include "system.hpp" + +namespace fs = boost::filesystem; + +namespace irccd { + +namespace { + +} // !namespace + +PluginLoader::PluginLoader(std::vector directories, + std::vector extensions) + : directories_(std::move(directories)) + , extensions_(std::move(extensions)) +{ +} + +std::shared_ptr PluginLoader::find(const std::string& name) noexcept +{ + if (extensions_.empty()) + return nullptr; + + std::vector filenames; + + if (directories_.empty()) + filenames = sys::plugin_filenames(name, extensions_); + else { + for (const auto& dir : directories_) + for (const auto& ext : extensions_) + filenames.push_back(dir + "/" + name + ext); + } + + std::shared_ptr plugin; + + for (const auto& candidate : filenames) { + boost::system::error_code ec; + + if (!boost::filesystem::exists(candidate, ec) || ec) + continue; + + plugin = open(name, candidate); + + if (plugin) + break; + } + + return plugin; +} + +} // !irccd diff -r daf3aa8b2ddb -r 0b156b82b8c1 libirccd/irccd/plugin.hpp --- a/libirccd/irccd/plugin.hpp Thu Jul 27 16:44:57 2017 +0200 +++ b/libirccd/irccd/plugin.hpp Thu Jul 20 15:12:41 2017 +0200 @@ -53,6 +53,11 @@ using PluginFormats = std::unordered_map; /** + * \brief Paths for plugins. + */ +using PluginPaths = std::unordered_map; + +/** * \ingroup plugins * \brief Abstract plugin. * @@ -231,6 +236,26 @@ } /** + * Access the plugin paths. + * + * \return the paths + */ + virtual PluginPaths paths() + { + return {}; + } + + /** + * Set the paths. + * + * \param paths the paths + */ + virtual void setPaths(PluginPaths paths) + { + util::unused(paths); + } + + /** * On channel message. This event will call onMessage or * onCommand if the messages starts with the command character * plus the plugin name. @@ -474,8 +499,47 @@ * \see JsPluginLoader */ class PluginLoader { +private: + std::vector directories_; + std::vector extensions_; + public: /** + * Construct the loader with a predefined set of directories and extensions. + * + * If directories is not specified, a sensible default list of system and + * user paths are searched. + * + * If extensions is empty, default find function implementation does + * nothing. + * + * \param directories directories to search + * \param extensions the list of extensions supported + */ + PluginLoader(std::vector directories = {}, + std::vector extensions = {}); + + /** + * Set directories where to search plugins. + * + * \param dirs the directories + */ + inline void set_directories(std::vector dirs) + { + directories_ = std::move(dirs); + } + + /** + * Set supported extensions for this loader. + * + * \param extensions the extensions (with the dot) + */ + inline void set_extensions(std::vector extensions) + { + extensions_ = std::move(extensions); + } + + /** * Try to open the plugin specified by path. * * The implementation must test if the plugin is suitable for opening, by @@ -492,7 +556,7 @@ * \param id the plugin id * \return the plugin */ - virtual std::shared_ptr find(const std::string &id) noexcept = 0; + virtual std::shared_ptr find(const std::string &id) noexcept; }; } // !irccd diff -r daf3aa8b2ddb -r 0b156b82b8c1 libirccd/irccd/service.cpp --- a/libirccd/irccd/service.cpp Thu Jul 27 16:44:57 2017 +0200 +++ b/libirccd/irccd/service.cpp Thu Jul 20 15:12:41 2017 +0200 @@ -26,9 +26,11 @@ #include "irccd.hpp" #include "logger.hpp" #include "service.hpp" +#include "system.hpp" #include "transport.hpp" using namespace fmt::literals; +using namespace std::string_literals; namespace irccd { @@ -125,6 +127,9 @@ PluginService::PluginService(Irccd &irccd) noexcept : m_irccd(irccd) { + m_default_paths.emplace("cache", sys::cachedir()); + m_default_paths.emplace("data", sys::datadir()); + m_default_paths.emplace("config", sys::sysconfigdir()); } PluginService::~PluginService() @@ -202,6 +207,40 @@ return PluginFormats(); } +const PluginPaths& PluginService::paths() const noexcept +{ + return m_default_paths; +} + +PluginPaths PluginService::paths(const std::string& name) const +{ + auto result = m_default_paths; + auto overriden = m_paths.find(name); + + // For all default paths, append the plugin name. + for (auto& pair : result) + pair.second += "/plugin/"s + name; + + // Now, mere overriden paths. + if (overriden != m_paths.end()) + for (const auto& pair : overriden->second) + result[pair.first] = pair.second; + + return result; +} + +void PluginService::setPaths(PluginPaths paths) +{ + // If the paths is empty or not complete, do not erase default items. + for (const auto& pair : paths) + m_default_paths[pair.first] = pair.second; +} + +void PluginService::setPaths(const std::string& name, PluginPaths paths) +{ + m_paths.emplace(name, std::move(paths)); +} + std::shared_ptr PluginService::open(const std::string &id, const std::string &path) { @@ -243,6 +282,7 @@ if (plugin) { plugin->setConfig(m_config[name]); plugin->setFormats(m_formats[name]); + plugin->setPaths(paths(name)); plugin->onLoad(m_irccd); add(std::move(plugin)); diff -r daf3aa8b2ddb -r 0b156b82b8c1 libirccd/irccd/service.hpp --- a/libirccd/irccd/service.hpp Thu Jul 27 16:44:57 2017 +0200 +++ b/libirccd/irccd/service.hpp Thu Jul 20 15:12:41 2017 +0200 @@ -138,10 +138,12 @@ class PluginService { private: Irccd &m_irccd; + PluginPaths m_default_paths; std::vector> m_plugins; std::vector> m_loaders; std::unordered_map m_config; std::unordered_map m_formats; + std::unordered_map m_paths; public: /** @@ -242,6 +244,36 @@ IRCCD_EXPORT PluginFormats formats(const std::string &name) const; /** + * Get the default paths for plugins. + * + * \return the paths + */ + IRCCD_EXPORT const PluginPaths& paths() const noexcept; + + /** + * Get the paths for the specified plugin. + * + * \param name the plugin + * \return the paths + */ + IRCCD_EXPORT PluginPaths paths(const std::string& name) const; + + /** + * Set default paths. + * + * \param paths the default paths (for all plugins) + */ + IRCCD_EXPORT void setPaths(PluginPaths paths); + + /** + * Override paths for the specified plugin. + * + * \param name the plugin name + * \param paths the paths + */ + void setPaths(const std::string& name, PluginPaths paths); + + /** * Generic function for opening the plugin at the given path. * * This function will search for every PluginLoader and call open() on it, diff -r daf3aa8b2ddb -r 0b156b82b8c1 plugins/ask/ask.js --- a/plugins/ask/ask.js Thu Jul 27 16:44:57 2017 +0200 +++ b/plugins/ask/ask.js Thu Jul 20 15:12:41 2017 +0200 @@ -43,7 +43,7 @@ if (Plugin.config["file"]) path = Plugin.config["file"]; else - path = Plugin.configPath + "answers.conf"; + path = Plugin.paths.config + "/answers.conf"; var file = new File(path, "r"); var line; diff -r daf3aa8b2ddb -r 0b156b82b8c1 plugins/hangman/hangman.js --- a/plugins/hangman/hangman.js Thu Jul 27 16:44:57 2017 +0200 +++ b/plugins/hangman/hangman.js Thu Jul 20 15:12:41 2017 +0200 @@ -132,7 +132,7 @@ if (Plugin.config["file"]) path = Plugin.config["file"]; else - path = Plugin.configPath + "words.conf"; + path = Plugin.paths.config + "/words.conf"; try { Logger.info("loading words..."); @@ -289,6 +289,7 @@ function onLoad() { + Logger.warning("TAMERE"); Hangman.loadFormats(); Hangman.loadWords(); } diff -r daf3aa8b2ddb -r 0b156b82b8c1 plugins/history/history.js --- a/plugins/history/history.js Thu Jul 27 16:44:57 2017 +0200 +++ b/plugins/history/history.js Thu Jul 20 15:12:41 2017 +0200 @@ -60,7 +60,7 @@ "channel": channel }); } else - p = Plugin.cachePath + "db.json"; + p = Plugin.paths.cache + "/db.json"; return p; } diff -r daf3aa8b2ddb -r 0b156b82b8c1 tests/CMakeLists.txt --- a/tests/CMakeLists.txt Thu Jul 27 16:44:57 2017 +0200 +++ b/tests/CMakeLists.txt Thu Jul 20 15:12:41 2017 +0200 @@ -53,10 +53,12 @@ # Misc add_subdirectory(elapsedtimer) add_subdirectory(logger) - add_subdirectory(path) add_subdirectory(rules) add_subdirectory(util) + # Services + add_subdirectory(service-plugin) + # JS API if (WITH_JS) add_subdirectory(js) diff -r daf3aa8b2ddb -r 0b156b82b8c1 tests/js-timer/main.cpp --- a/tests/js-timer/main.cpp Thu Jul 27 16:44:57 2017 +0200 +++ b/tests/js-timer/main.cpp Thu Jul 20 15:12:41 2017 +0200 @@ -103,7 +103,6 @@ { // Needed for some components. sys::setProgramName("irccd"); - path::setApplicationPath(argv[0]); log::setLogger(std::make_unique()); log::setVerbose(true); testing::InitGoogleTest(&argc, argv); diff -r daf3aa8b2ddb -r 0b156b82b8c1 tests/path/CMakeLists.txt --- a/tests/path/CMakeLists.txt Thu Jul 27 16:44:57 2017 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,23 +0,0 @@ -# -# CMakeLists.txt -- CMake build system for irccd -# -# Copyright (c) 2013-2017 David Demelier -# -# 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. -# - -irccd_define_test( - NAME path - SOURCES main.cpp - LIBRARIES libirccd -) diff -r daf3aa8b2ddb -r 0b156b82b8c1 tests/path/main.cpp --- a/tests/path/main.cpp Thu Jul 27 16:44:57 2017 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,145 +0,0 @@ -/* - * main.cpp -- test path functions - * - * Copyright (c) 2013-2017 David Demelier - * - * 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 - -#include -#include -#include - -namespace irccd { - -/* -------------------------------------------------------- - * Back slashes - * -------------------------------------------------------- */ - -#if defined(IRCCD_SYSTEM_WINDOWS) - -TEST(Back, nochange) -{ - std::string path = "\\usr\\local\\etc\\"; - std::string result = path::clean(path); - - ASSERT_EQ(path, result); -} - -TEST(Back, duplicateBegin) -{ - std::string path = "\\\\usr\\local\\etc\\"; - std::string result = path::clean(path); - - ASSERT_EQ("\\usr\\local\\etc\\", result); -} - -TEST(Back, duplicateEnd) -{ - std::string path = "\\usr\\local\\etc\\\\"; - std::string result = path::clean(path); - - ASSERT_EQ("\\usr\\local\\etc\\", result); -} - -TEST(Back, duplicateEverywhere) -{ - std::string path = "\\\\usr\\\\local\\\\etc\\\\"; - std::string result = path::clean(path); - - ASSERT_EQ("\\usr\\local\\etc\\", result); -} - -TEST(Back, missingTrailing) -{ - std::string path = "\\usr\\local\\etc"; - std::string result = path::clean(path); - - ASSERT_EQ("\\usr\\local\\etc\\", result); -} - -#else - -/* -------------------------------------------------------- - * Forward slashes - * -------------------------------------------------------- */ - -TEST(Forward, nochange) -{ - std::string path = "/usr/local/etc/"; - std::string result = path::clean(path); - - ASSERT_EQ(path, result); -} - -TEST(Forward, duplicateBegin) -{ - std::string path = "//usr/local/etc/"; - std::string result = path::clean(path); - - ASSERT_EQ("/usr/local/etc/", result); -} - -TEST(Forward, duplicateEnd) -{ - std::string path = "/usr/local/etc//"; - std::string result = path::clean(path); - - ASSERT_EQ("/usr/local/etc/", result); -} - -TEST(Forward, duplicateEverywhere) -{ - std::string path = "//usr//local//etc//"; - std::string result = path::clean(path); - - ASSERT_EQ("/usr/local/etc/", result); -} - -TEST(Forward, missingTrailing) -{ - std::string path = "/usr/local/etc"; - std::string result = path::clean(path); - - ASSERT_EQ("/usr/local/etc/", result); -} - -#endif - -} // !irccd - -using namespace irccd; - -int main(int argc, char **argv) -{ - /* - * Just show everything for test purpose. - */ - path::setApplicationPath(argv[0]); - log::debug() << "System paths:" << std::endl; - log::debug() << " config(system): " << path::get(path::PathConfig, path::OwnerSystem) << std::endl; - log::debug() << " data(system): " << path::get(path::PathData, path::OwnerSystem) << std::endl; - log::debug() << " plugins(system): " << path::get(path::PathPlugins, path::OwnerSystem) << std::endl; - log::debug() << " cache(system): " << path::get(path::PathCache, path::OwnerSystem) << std::endl; - log::debug() << "User paths:" << std::endl; - log::debug() << " config(user): " << path::get(path::PathConfig, path::OwnerUser) << std::endl; - log::debug() << " data(user): " << path::get(path::PathData, path::OwnerUser) << std::endl; - log::debug() << " plugins(user): " << path::get(path::PathPlugins, path::OwnerUser) << std::endl; - log::debug() << " cache(user): " << path::get(path::PathCache, path::OwnerUser) << std::endl; - - testing::InitGoogleTest(&argc, argv); - - return RUN_ALL_TESTS(); -} diff -r daf3aa8b2ddb -r 0b156b82b8c1 tests/plugin-ask/main.cpp --- a/tests/plugin-ask/main.cpp Thu Jul 27 16:44:57 2017 +0200 +++ b/tests/plugin-ask/main.cpp Thu Jul 20 15:12:41 2017 +0200 @@ -21,7 +21,6 @@ #include #include #include -#include #include "plugin-tester.hpp" @@ -87,7 +86,6 @@ int main(int argc, char **argv) { - path::setApplicationPath(argv[0]); testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); diff -r daf3aa8b2ddb -r 0b156b82b8c1 tests/plugin-auth/main.cpp --- a/tests/plugin-auth/main.cpp Thu Jul 27 16:44:57 2017 +0200 +++ b/tests/plugin-auth/main.cpp Thu Jul 20 15:12:41 2017 +0200 @@ -21,7 +21,6 @@ #include #include #include -#include #include "plugin-tester.hpp" @@ -99,7 +98,6 @@ int main(int argc, char **argv) { - path::setApplicationPath(argv[0]); testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); diff -r daf3aa8b2ddb -r 0b156b82b8c1 tests/plugin-hangman/main.cpp --- a/tests/plugin-hangman/main.cpp Thu Jul 27 16:44:57 2017 +0200 +++ b/tests/plugin-hangman/main.cpp Thu Jul 20 15:12:41 2017 +0200 @@ -24,7 +24,6 @@ #include #include #include -#include #include "plugin-tester.hpp" @@ -293,7 +292,6 @@ int main(int argc, char **argv) { - path::setApplicationPath(argv[0]); testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); diff -r daf3aa8b2ddb -r 0b156b82b8c1 tests/plugin-history/main.cpp --- a/tests/plugin-history/main.cpp Thu Jul 27 16:44:57 2017 +0200 +++ b/tests/plugin-history/main.cpp Thu Jul 20 15:12:41 2017 +0200 @@ -23,7 +23,6 @@ #include #include #include -#include #include "plugin-tester.hpp" @@ -141,7 +140,6 @@ int main(int argc, char **argv) { - path::setApplicationPath(argv[0]); testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); diff -r daf3aa8b2ddb -r 0b156b82b8c1 tests/plugin-logger/main.cpp --- a/tests/plugin-logger/main.cpp Thu Jul 27 16:44:57 2017 +0200 +++ b/tests/plugin-logger/main.cpp Thu Jul 20 15:12:41 2017 +0200 @@ -25,7 +25,6 @@ #include #include #include -#include #include "plugin-tester.hpp" @@ -193,7 +192,6 @@ int main(int argc, char **argv) { - path::setApplicationPath(argv[0]); testing::InitGoogleTest(&argc, argv); log::setLogger(std::make_unique()); diff -r daf3aa8b2ddb -r 0b156b82b8c1 tests/plugin-plugin/main.cpp --- a/tests/plugin-plugin/main.cpp Thu Jul 27 16:44:57 2017 +0200 +++ b/tests/plugin-plugin/main.cpp Thu Jul 20 15:12:41 2017 +0200 @@ -24,7 +24,6 @@ #include #include #include -#include #include "plugin-tester.hpp" @@ -124,7 +123,6 @@ int main(int argc, char **argv) { - path::setApplicationPath(argv[0]); testing::InitGoogleTest(&argc, argv); log::setLogger(std::make_unique()); diff -r daf3aa8b2ddb -r 0b156b82b8c1 tests/service-plugin/CMakeLists.txt --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/service-plugin/CMakeLists.txt Thu Jul 20 15:12:41 2017 +0200 @@ -0,0 +1,24 @@ +# +# CMakeLists.txt -- CMake build system for irccd +# +# Copyright (c) 2013-2017 David Demelier +# +# 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. +# + +irccd_define_test( + NAME service-plugin + SOURCES main.cpp + LIBRARIES libirccd +) + diff -r daf3aa8b2ddb -r 0b156b82b8c1 tests/service-plugin/main.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/service-plugin/main.cpp Thu Jul 20 15:12:41 2017 +0200 @@ -0,0 +1,153 @@ +/* + * main.cpp -- test irccd rules + * + * Copyright (c) 2013-2017 David Demelier + * + * 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 + +#include +#include + +namespace irccd { + +TEST(service_plugin, default_paths) +{ + Irccd irccd; + + irccd.plugins().setPaths({ + { "cache", "/var/cache/irccd" }, + { "config", "/etc/irccd" }, + { "data", "/usr/local/share/irccd" } + }); + + auto paths = irccd.plugins().paths("ask"); + + ASSERT_EQ("/var/cache/irccd/plugin/ask", paths["cache"]); + ASSERT_EQ("/etc/irccd/plugin/ask", paths["config"]); + ASSERT_EQ("/usr/local/share/irccd/plugin/ask", paths["data"]); +} + +TEST(service_plugin, override_cache) +{ + Irccd irccd; + + irccd.plugins().setPaths({ + { "cache", "/var/cache/irccd" }, + { "config", "/etc/irccd" }, + { "data", "/usr/local/share/irccd" } + }); + irccd.plugins().setPaths("ask", { + { "cache", "/opt/cache/ask" } + }); + + auto paths = irccd.plugins().paths("ask"); + + ASSERT_EQ("/opt/cache/ask", paths["cache"]); + ASSERT_EQ("/etc/irccd/plugin/ask", paths["config"]); + ASSERT_EQ("/usr/local/share/irccd/plugin/ask", paths["data"]); +} + +TEST(service_plugin, override_config) +{ + Irccd irccd; + + irccd.plugins().setPaths({ + { "cache", "/var/cache/irccd" }, + { "config", "/etc/irccd" }, + { "data", "/usr/local/share/irccd" } + }); + irccd.plugins().setPaths("ask", { + { "config", "/opt/config/ask" } + }); + + auto paths = irccd.plugins().paths("ask"); + + ASSERT_EQ("/var/cache/irccd/plugin/ask", paths["cache"]); + ASSERT_EQ("/opt/config/ask", paths["config"]); + ASSERT_EQ("/usr/local/share/irccd/plugin/ask", paths["data"]); +} + +TEST(service_plugin, override_data) +{ + Irccd irccd; + + irccd.plugins().setPaths({ + { "cache", "/var/cache/irccd" }, + { "config", "/etc/irccd" }, + { "data", "/usr/local/share/irccd" } + }); + irccd.plugins().setPaths("ask", { + { "data", "/opt/data/ask" } + }); + + auto paths = irccd.plugins().paths("ask"); + + ASSERT_EQ("/var/cache/irccd/plugin/ask", paths["cache"]); + ASSERT_EQ("/etc/irccd/plugin/ask", paths["config"]); + ASSERT_EQ("/opt/data/ask", paths["data"]); +} + +TEST(service_plugin, override_all) +{ + Irccd irccd; + + irccd.plugins().setPaths({ + { "cache", "/var/cache/irccd" }, + { "config", "/etc/irccd" }, + { "data", "/usr/local/share/irccd" } + }); + irccd.plugins().setPaths("ask", { + { "cache", "/opt/cache/ask" }, + { "config", "/opt/config/ask" }, + { "data", "/opt/data/ask" } + }); + + auto paths = irccd.plugins().paths("ask"); + + ASSERT_EQ("/opt/cache/ask", paths["cache"]); + ASSERT_EQ("/opt/config/ask", paths["config"]); + ASSERT_EQ("/opt/data/ask", paths["data"]); +} + +TEST(service_plugin, extra_paths) +{ + Irccd irccd; + + irccd.plugins().setPaths({ + { "cache", "/var/cache/irccd" }, + { "config", "/etc/irccd" }, + { "data", "/usr/local/share/irccd" } + }); + irccd.plugins().setPaths("ask", { + { "extra", "/opt/magic" } + }); + + auto paths = irccd.plugins().paths("ask"); + + ASSERT_EQ("/var/cache/irccd/plugin/ask", paths["cache"]); + ASSERT_EQ("/etc/irccd/plugin/ask", paths["config"]); + ASSERT_EQ("/usr/local/share/irccd/plugin/ask", paths["data"]); + ASSERT_EQ("/opt/magic", paths["extra"]); +} + +} // !irccd + +int main(int argc, char **argv) +{ + testing::InitGoogleTest(&argc, argv); + + return RUN_ALL_TESTS(); +}