use setup.ini to retrieve the modulepath and configpath
connect config-facade with the new BasicSetup implementation to fetch values from setup.ini, instead of the (not implemented) Config-system. Hook this new lookup mechanism into the plugin loader to retrieve the search path from there
This commit is contained in:
parent
87475fa3c1
commit
88678209bc
12 changed files with 183 additions and 70 deletions
|
|
@ -10,3 +10,5 @@
|
||||||
#
|
#
|
||||||
gui = gtk_gui.lum
|
gui = gtk_gui.lum
|
||||||
modulepath = $ORIGIN/modules
|
modulepath = $ORIGIN/modules
|
||||||
|
configpath = /usr/share/lumiera/config:~/.lumiera
|
||||||
|
version = 0.pre.01
|
||||||
|
|
|
||||||
|
|
@ -36,9 +36,10 @@ extern "C" {
|
||||||
|
|
||||||
#include "lib/symbol.hpp"
|
#include "lib/symbol.hpp"
|
||||||
#include "lib/util.hpp"
|
#include "lib/util.hpp"
|
||||||
#include "include/configfacade.hpp" //////////TODO: temp hack to force configfacade.o to be linked in
|
|
||||||
|
|
||||||
using util::cStr;
|
using util::cStr;
|
||||||
|
using lib::Literal;
|
||||||
|
|
||||||
|
|
||||||
#define LOCATION_OF_BOOTSTRAP_INI "$ORIGIN/config/setup.ini"
|
#define LOCATION_OF_BOOTSTRAP_INI "$ORIGIN/config/setup.ini"
|
||||||
|
|
@ -98,6 +99,13 @@ namespace lumiera {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
string
|
||||||
|
AppState::fetchSetupValue (Literal key)
|
||||||
|
{
|
||||||
|
return setup_.get(key).as<string>();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -191,8 +199,6 @@ namespace lumiera {
|
||||||
AppState::abort (lumiera::Error& problem)
|
AppState::abort (lumiera::Error& problem)
|
||||||
{
|
{
|
||||||
|
|
||||||
INFO (common, "Address of Config Facade = %p", &lumiera::Config::instance()); //////////TODO: a temp hack to force configfacade.cpp to be linked into lumiera exe.
|
|
||||||
|
|
||||||
ERROR (common, "Aborting Lumiera after unhandled error: %s", cStr(problem.what()));
|
ERROR (common, "Aborting Lumiera after unhandled error: %s", cStr(problem.what()));
|
||||||
|
|
||||||
log_and_clear_unexpected_errorstate();
|
log_and_clear_unexpected_errorstate();
|
||||||
|
|
|
||||||
|
|
@ -90,6 +90,10 @@ namespace lumiera {
|
||||||
void init (lumiera::Option& options);
|
void init (lumiera::Option& options);
|
||||||
|
|
||||||
|
|
||||||
|
/** access basic application setup values (from \c setup.ini) */
|
||||||
|
string fetchSetupValue (lib::Literal key);
|
||||||
|
|
||||||
|
|
||||||
/** building on the state determined by #evaluate, decide if the given Subsys
|
/** building on the state determined by #evaluate, decide if the given Subsys
|
||||||
* needs to be pulled up and, if necessary, register the Subsys and its
|
* needs to be pulled up and, if necessary, register the Subsys and its
|
||||||
* prerequisites to be maintained throughout the application's lifetime. */
|
* prerequisites to be maintained throughout the application's lifetime. */
|
||||||
|
|
|
||||||
|
|
@ -74,11 +74,17 @@ namespace lumiera {
|
||||||
, settings()
|
, settings()
|
||||||
{
|
{
|
||||||
syntax.add_options()
|
syntax.add_options()
|
||||||
("BuildsystemDemo.gui", opt::value<string>(),
|
("Lumiera.gui", opt::value<string>(),
|
||||||
"name of the Lumiera GUI plugin to load")
|
"name of the Lumiera GUI plugin to load")
|
||||||
("BuildsystemDemo.modulepath", opt::value<string>(),
|
("Lumiera.modulepath", opt::value<string>(),
|
||||||
"search path for loadable modules. "
|
"search path for loadable modules. "
|
||||||
"May us $ORIGIN to refer to the EXE location")
|
"May us $ORIGIN to refer to the EXE location")
|
||||||
|
("Lumiera.configpath", opt::value<string>(),
|
||||||
|
"search path for extended configuration. "
|
||||||
|
"Extended Config system not yet implemented "
|
||||||
|
"Ignored as of 2/2011")
|
||||||
|
("Lumiera.version", opt::value<string>(),
|
||||||
|
"Application version string")
|
||||||
;
|
;
|
||||||
|
|
||||||
ifstream configIn (resolve(bootstrapIni).c_str());
|
ifstream configIn (resolve(bootstrapIni).c_str());
|
||||||
|
|
|
||||||
|
|
@ -25,6 +25,8 @@
|
||||||
#define COMMON_BASIC_SETUP_H
|
#define COMMON_BASIC_SETUP_H
|
||||||
|
|
||||||
#include "lib/error.hpp"
|
#include "lib/error.hpp"
|
||||||
|
#include "lib/symbol.hpp"
|
||||||
|
#include "lib/util.hpp"
|
||||||
|
|
||||||
#include <boost/program_options.hpp>
|
#include <boost/program_options.hpp>
|
||||||
#include <boost/noncopyable.hpp>
|
#include <boost/noncopyable.hpp>
|
||||||
|
|
@ -68,19 +70,27 @@ namespace lumiera {
|
||||||
BasicSetup (string bootstrapIni);
|
BasicSetup (string bootstrapIni);
|
||||||
|
|
||||||
string
|
string
|
||||||
operator[] (string const& key) const
|
operator[] (lib::Literal key) const
|
||||||
{
|
{
|
||||||
return settings[key].as<string>();
|
return get (key).as<string>();
|
||||||
}
|
}
|
||||||
|
|
||||||
opt::variable_value const&
|
opt::variable_value const&
|
||||||
get (string const& key)
|
get (lib::Literal key) const
|
||||||
{
|
{
|
||||||
return settings[key];
|
string keyID (key);
|
||||||
|
__ensure_hasKey(keyID);
|
||||||
|
return settings[keyID];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
void
|
||||||
|
__ensure_hasKey (string const& key) const
|
||||||
|
{
|
||||||
|
if (!util::contains (settings, key))
|
||||||
|
throw error::Logic ("Key \""+key+"\" not found in setup.ini");
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -23,20 +23,39 @@
|
||||||
|
|
||||||
#include "include/logging.h"
|
#include "include/logging.h"
|
||||||
#include "include/lifecycle.h"
|
#include "include/lifecycle.h"
|
||||||
#include "include/configfacade.hpp"
|
#include "include/config-facade.h"
|
||||||
|
#include "common/appstate.hpp"
|
||||||
|
#include "lib/searchpath.hpp"
|
||||||
|
#include "lib/util.hpp"
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#include "common/config.h"
|
#include "common/config.h"
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef LUMIERA_CONFIG_PATH
|
|
||||||
#error LUMIERA_CONFIG_PATH not defined
|
/** key to fetch the search path for extended configuration.
|
||||||
#endif
|
* Will corresponding value is defined in the basic setup.ini
|
||||||
|
* and will be fed to the (planned) full-blown config system
|
||||||
|
* after the basic application bootstrap was successful.
|
||||||
|
*/
|
||||||
|
#define KEY_CONFIG_PATH "Lumiera.configpath"
|
||||||
|
|
||||||
|
/** Similarly, this key is used to fetch the configured default
|
||||||
|
* plugin/module search path from the basic setup.ini
|
||||||
|
* This patch is used by the plugin-loader to discover
|
||||||
|
* lumiera plugins and extensions.
|
||||||
|
*/
|
||||||
|
#define KEY_PLUGIN_PATH "Lumiera.modulepath"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
namespace lumiera {
|
namespace lumiera {
|
||||||
|
|
||||||
|
using util::cStr;
|
||||||
|
using util::isnil;
|
||||||
|
using lib::Literal;
|
||||||
|
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
|
|
@ -59,28 +78,63 @@ namespace lumiera {
|
||||||
|
|
||||||
Config::Config ()
|
Config::Config ()
|
||||||
{
|
{
|
||||||
lumiera_config_init (LUMIERA_CONFIG_PATH);
|
string extendedConfigSearchPath = AppState::instance().fetchSetupValue (KEY_CONFIG_PATH);
|
||||||
|
lumiera_config_init (cStr(extendedConfigSearchPath));
|
||||||
INFO (config, "Config system ready.");
|
INFO (config, "Config system ready.");
|
||||||
|
|
||||||
TODO ("wire Config facade to config interface");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Config::~Config()
|
Config::~Config()
|
||||||
{
|
{
|
||||||
lumiera_config_destroy();
|
lumiera_config_destroy();
|
||||||
TRACE (common, "config system closed.");
|
TRACE (config, "config system closed.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
const string
|
/** @note because the full-blown Config system isn't implemented yet
|
||||||
Config::get (string const& key)
|
* we retrieve the contents of setup.ini as a preliminary solution
|
||||||
|
*/
|
||||||
|
string
|
||||||
|
Config::get (lib::Literal key)
|
||||||
{
|
{
|
||||||
UNIMPLEMENTED ("config facade access to config value");
|
string value = AppState::instance().fetchSetupValue (key);
|
||||||
return string("warwohlnix");
|
if (isnil (value))
|
||||||
|
throw error::Config ("Configuration value for key=\""+key+"\" is missing");
|
||||||
|
|
||||||
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
} // namespace lumiera
|
} // namespace lumiera
|
||||||
|
|
||||||
|
|
||||||
|
extern "C" { /* ==== implementation C interface for accessing setup.ini ======= */
|
||||||
|
|
||||||
|
|
||||||
|
using std::string;
|
||||||
|
using lumiera::Config;
|
||||||
|
using lib::SearchPathSplitter;
|
||||||
|
using util::isnil;
|
||||||
|
using util::cStr;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
const char*
|
||||||
|
lumiera_get_plugin_path_default ()
|
||||||
|
{
|
||||||
|
static string pathSpec;
|
||||||
|
if (isnil (pathSpec))
|
||||||
|
{
|
||||||
|
pathSpec += "plugin.path="; // syntax expected by lumiera_config_setdefault
|
||||||
|
|
||||||
|
// fetch plugin search path from setup.ini and expand any $ORIGIN token
|
||||||
|
SearchPathSplitter pathElement(Config::get (KEY_PLUGIN_PATH));
|
||||||
|
while (pathElement)
|
||||||
|
pathSpec += pathElement.fetch() +":";
|
||||||
|
}
|
||||||
|
|
||||||
|
return cStr(pathSpec);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,13 @@
|
||||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/** @file plugin.c
|
||||||
|
** Plugin loader implementation.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#include "include/logging.h"
|
#include "include/logging.h"
|
||||||
#include "lib/safeclib.h"
|
#include "lib/safeclib.h"
|
||||||
#include "lib/tmpbuf.h"
|
#include "lib/tmpbuf.h"
|
||||||
|
|
@ -26,6 +33,7 @@
|
||||||
#include "lib/recmutex.h"
|
#include "lib/recmutex.h"
|
||||||
#include "lib/error.h"
|
#include "lib/error.h"
|
||||||
|
|
||||||
|
#include "include/config-facade.h"
|
||||||
#include "common/interfaceregistry.h"
|
#include "common/interfaceregistry.h"
|
||||||
#include "common/config.h"
|
#include "common/config.h"
|
||||||
#include "common/plugin.h"
|
#include "common/plugin.h"
|
||||||
|
|
@ -34,23 +42,15 @@
|
||||||
|
|
||||||
#include <nobug.h>
|
#include <nobug.h>
|
||||||
|
|
||||||
#ifndef LUMIERA_PLUGIN_PATH
|
|
||||||
#error please define the plugin search path as -DLUMIERA_PLUGIN_PATH, e.g. as $INSTALL_PREFIX/lib/lumiera
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @file
|
|
||||||
* Plugin loader.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* just some declarations */
|
|
||||||
extern PSplay lumiera_pluginregistry;
|
extern PSplay lumiera_pluginregistry;
|
||||||
static char* init_exts_globs (void);
|
static char* init_exts_globs (void);
|
||||||
|
|
||||||
/* TODO default plugin path should be set by the build system */
|
|
||||||
|
|
||||||
/* errors */
|
/* errors */
|
||||||
LUMIERA_ERROR_DEFINE(PLUGIN_INIT, "Initialization error");
|
LUMIERA_ERROR_DEFINE(PLUGIN_INIT, "Initialisation error");
|
||||||
LUMIERA_ERROR_DEFINE(PLUGIN_OPEN, "Could not open plugin");
|
LUMIERA_ERROR_DEFINE(PLUGIN_OPEN, "Could not open plugin");
|
||||||
LUMIERA_ERROR_DEFINE(PLUGIN_WTF, "Not a Lumiera plugin");
|
LUMIERA_ERROR_DEFINE(PLUGIN_WTF, "Not a Lumiera plugin");
|
||||||
LUMIERA_ERROR_DEFINE(PLUGIN_REGISTER, "Could not register plugin");
|
LUMIERA_ERROR_DEFINE(PLUGIN_REGISTER, "Could not register plugin");
|
||||||
|
|
@ -61,7 +61,7 @@ LUMIERA_ERROR_DEFINE(PLUGIN_VERSION, "Plugin Version unsupported");
|
||||||
/**
|
/**
|
||||||
* Supported (and planned) plugin types and their file extensions
|
* Supported (and planned) plugin types and their file extensions
|
||||||
* This maps filename extensions to implementations (of the respective _load_NAME and _unload_NAME functions)
|
* This maps filename extensions to implementations (of the respective _load_NAME and _unload_NAME functions)
|
||||||
* So far we only support platform dynamic libraries, later we may add plugins implemented in lua
|
* So far we only support platform dynamic libraries, later we may add plugins implemented in Lua
|
||||||
* and c source modules which get compiled on the fly.
|
* and c source modules which get compiled on the fly.
|
||||||
*/
|
*/
|
||||||
#define LUMIERA_PLUGIN_TYPES \
|
#define LUMIERA_PLUGIN_TYPES \
|
||||||
|
|
@ -115,7 +115,8 @@ struct lumiera_plugin_struct
|
||||||
/* time when the refcounter dropped to 0 last time */
|
/* time when the refcounter dropped to 0 last time */
|
||||||
time_t last;
|
time_t last;
|
||||||
|
|
||||||
/* when loading plugins en masse we do not want to fail completely if one doesnt cooperate, instead we record local errors here */
|
/** bulk loading plugins must not fail entirely, just because one
|
||||||
|
* plugin doesn't comply. Thus we're recording local errors here */
|
||||||
lumiera_err error;
|
lumiera_err error;
|
||||||
|
|
||||||
/* the 'plugin' interface itself */
|
/* the 'plugin' interface itself */
|
||||||
|
|
@ -198,9 +199,12 @@ lumiera_plugin_discover (LumieraPlugin (*callback_load)(const char* plugin),
|
||||||
REQUIRE (callback_load);
|
REQUIRE (callback_load);
|
||||||
REQUIRE (callback_register);
|
REQUIRE (callback_register);
|
||||||
|
|
||||||
lumiera_config_setdefault ("plugin.path ="LUMIERA_PLUGIN_PATH);
|
// Note: because the full-blown Config system isn't implemented yet,
|
||||||
|
// as a temporary solution we fetch this basic configuration
|
||||||
|
// from the setup.ini used to bootstrap the application
|
||||||
|
lumiera_config_setdefault (lumiera_get_plugin_path_default());
|
||||||
|
|
||||||
/* construct glob trail {.so,.c,.foo} ... */
|
/* construct glob trail {.so,.lum,.lua} ... */
|
||||||
static char* exts_globs = NULL;
|
static char* exts_globs = NULL;
|
||||||
if (!exts_globs)
|
if (!exts_globs)
|
||||||
exts_globs = init_exts_globs ();
|
exts_globs = init_exts_globs ();
|
||||||
|
|
@ -375,7 +379,7 @@ static char* init_exts_globs (void)
|
||||||
++itr;
|
++itr;
|
||||||
}
|
}
|
||||||
exts_globs[exts_sz-2] = '}';
|
exts_globs[exts_sz-2] = '}';
|
||||||
TRACE (pluginloader_dbg, "initialized extension glob to '%s'", exts_globs);
|
TRACE (pluginloader_dbg, "initialised extension glob to '%s'", exts_globs);
|
||||||
return exts_globs;
|
return exts_globs;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -20,12 +20,15 @@
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/** @file configfacade.hpp
|
/** @file configfacade.h
|
||||||
** The lumiera::Config wrapper class addresses two issues.
|
** The lumiera::Config wrapper class addresses two issues.
|
||||||
** First, it registers startup and shutdown hooks to bring up the config system
|
** First, it registers startup and shutdown hooks to bring up the config system
|
||||||
** as early as possible. Later, on application main initialisation, the global
|
** as early as possible. Later, on application main initialisation, the global
|
||||||
** config interface is opened and wrapped for convenient access from C++ code.
|
** config interface is opened and wrapped for convenient access from C++ code.
|
||||||
**
|
**
|
||||||
|
** @todo there ought to be an external Interface for the Config subsystem.
|
||||||
|
** But the full-blown Config system isn't implemented yet anyway
|
||||||
|
**
|
||||||
** @see config.h
|
** @see config.h
|
||||||
** @see lumiera::AppState
|
** @see lumiera::AppState
|
||||||
** @see main.cpp
|
** @see main.cpp
|
||||||
|
|
@ -36,7 +39,13 @@
|
||||||
#define INTERFACE_CONFIGFACADE_H
|
#define INTERFACE_CONFIGFACADE_H
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef __cplusplus /* ============== C++ Interface ================= */
|
||||||
|
|
||||||
#include "lib/singleton.hpp"
|
#include "lib/singleton.hpp"
|
||||||
|
#include "lib/symbol.hpp"
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
|
|
@ -56,7 +65,7 @@ namespace lumiera {
|
||||||
class Config
|
class Config
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
static const string get (string const& key);
|
static string get (lib::Literal key);
|
||||||
|
|
||||||
static lib::Singleton<Config> instance;
|
static lib::Singleton<Config> instance;
|
||||||
|
|
||||||
|
|
@ -70,4 +79,20 @@ namespace lumiera {
|
||||||
|
|
||||||
|
|
||||||
} // namespace lumiera
|
} // namespace lumiera
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#else /* =========================== C Interface ====================== */
|
||||||
|
|
||||||
|
|
||||||
|
/** retrieve the default plugin search path from the
|
||||||
|
* basic applications setup.ini
|
||||||
|
* @return a fully expanded string suitable to be fed
|
||||||
|
* to the lumiera_config_setdefault function
|
||||||
|
* @see lumiera_plugin_discover
|
||||||
|
*/
|
||||||
|
const char* lumiera_get_plugin_path_default ();
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
@ -98,4 +98,3 @@ extern "C" { /* ==== implementation C interface for lifecycle hooks ======= */
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -6,11 +6,11 @@ out: found plugin: \(null\)
|
||||||
return: 0
|
return: 0
|
||||||
END
|
END
|
||||||
|
|
||||||
export LUMIERA_PLUGIN_PATH=.libs
|
export LUMIERA_PLUGIN_PATH=modules
|
||||||
export LUMIERA_CONFIG_PATH=./
|
export LUMIERA_CONFIG_PATH=./
|
||||||
|
|
||||||
TEST "discovering plugins" plugin_discover <<END
|
TEST "discovering plugins" plugin_discover <<END
|
||||||
out: found plugin: \.libs/examplepluginc.lum
|
out: found plugin: modules/examplepluginc.lum
|
||||||
return: 0
|
return: 0
|
||||||
END
|
END
|
||||||
|
|
||||||
|
|
@ -29,7 +29,7 @@ END
|
||||||
|
|
||||||
TEST "C plugin test, nested" plugin_examplepluginc_nested <<END
|
TEST "C plugin test, nested" plugin_examplepluginc_nested <<END
|
||||||
out: config path is: \./
|
out: config path is: \./
|
||||||
out: plugin path is: \.libs
|
out: plugin path is: modules
|
||||||
out: Hallo Welt!
|
out: Hallo Welt!
|
||||||
out: Hello World!
|
out: Hello World!
|
||||||
out: Bye World!
|
out: Bye World!
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,7 @@ return: 0
|
||||||
END
|
END
|
||||||
|
|
||||||
|
|
||||||
PLANNED "basic application state" Appconfig_test <<END
|
TEST "basic application state" Appconfig_test <<END
|
||||||
return: 0
|
return: 0
|
||||||
END
|
END
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -23,10 +23,12 @@
|
||||||
|
|
||||||
|
|
||||||
#include "lib/test/run.hpp"
|
#include "lib/test/run.hpp"
|
||||||
|
#include "include/config-facade.h"
|
||||||
|
#include "lib/symbol.hpp"
|
||||||
#include "lib/util.hpp"
|
#include "lib/util.hpp"
|
||||||
|
|
||||||
#include "common/appstate.hpp"
|
using lib::Literal;
|
||||||
|
using util::isnil;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -36,24 +38,25 @@ namespace lumiera {
|
||||||
|
|
||||||
class Appconfig_test : public Test
|
class Appconfig_test : public Test
|
||||||
{
|
{
|
||||||
virtual void run (Arg arg)
|
virtual void
|
||||||
|
run (Arg)
|
||||||
{
|
{
|
||||||
testAccess("version");
|
fetchSetupValue();
|
||||||
UNIMPLEMENTED ("reorganise config access for C++");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @test accessing a value from lumiera::AppState */
|
|
||||||
void testAccess (const string& key)
|
/** @test accessing a value from setup.ini */
|
||||||
|
void fetchSetupValue ()
|
||||||
{
|
{
|
||||||
// string ver = lumiera::AppState::get(key);
|
Literal key("Lumiera.version");
|
||||||
// CHECK ( !util::isnil(ver));
|
string ver = Config::get(key);
|
||||||
|
CHECK (!isnil(ver));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
LAUNCHER (Appconfig_test, "function common");
|
LAUNCHER (Appconfig_test, "function common");
|
||||||
|
|
||||||
|
|
||||||
} // namespace test
|
}} // namespace util::test
|
||||||
|
|
||||||
} // namespace util
|
|
||||||
|
|
||||||
Loading…
Reference in a new issue