refactor some lib facilities

- Cmdline into namespace lib
- test coverage for the SearchPath iterator
This commit is contained in:
Fischlurch 2011-02-05 23:53:37 +01:00
parent e73bea379c
commit e84ceec9b5
22 changed files with 422 additions and 61 deletions

View file

@ -34,6 +34,7 @@ extern "C" {
#include "common/plugin.h"
}
#include "lib/symbol.hpp"
#include "lib/util.hpp"
#include "include/configfacade.hpp" //////////TODO: temp hack to force configfacade.o to be linked in
@ -59,6 +60,7 @@ namespace lumiera {
LifecycleHook schedule_ (ON_BASIC_INIT, &createAppStateInstance);
lib::Literal GET_PATH_TO_EXECUTABLE ("/proc/self/exe");
}

View file

@ -6,6 +6,7 @@
#include "lib/error.hpp"
#include "common/bootstrap.hpp"
extern "C" {

View file

@ -7,8 +7,6 @@
#ifndef COMMON_DUMMY_FUNC_H
#define COMMON_DUMMY_FUNC_H
#include "include/nobugcfg.h"
#include <string>

View file

@ -33,7 +33,7 @@ typedef boost::program_options::variables_map VarMap;
namespace op = boost::program_options;
using util::VectS;
using lib::VectS;
using util::cStr;
@ -50,7 +50,7 @@ namespace lumiera {
* \endcode
* @todo describe the actual options
*/
Option::Option (util::Cmdline& cmdline)
Option::Option (lib::Cmdline& cmdline)
: syntax("Lumiera, the non linear video editor. Supported parameters"),
parameters()
{

View file

@ -37,13 +37,13 @@ namespace lumiera {
using std::string;
using std::ostream;
using util::VectS;
using lib::VectS;
/**
* Support for selecting and configuring testcases
* via commandline arguments. A preconfigured wrapper
* Frontend for handling the Lumiera application
* commandline arguments. A preconfigured wrapper
* around boost::program_options, with the ability
* to tolerate unknown options. The commandline
* to be parsed is taken wrapped into a Cmdline
@ -54,7 +54,7 @@ namespace lumiera {
class Option : private boost::noncopyable
{
public:
Option (util::Cmdline& cmdline);
Option (lib::Cmdline& cmdline);
const string getSessName();
const VectS getScripts();

View file

@ -3,8 +3,8 @@
Copyright (C) Lumiera.org
2007-2008, Joel Holdsworth <joel@airwebreathe.org.uk>
2009, Christian Thaeter <ct@pipapo.org>
Hermann Vosseler <Ichthyostega@web.de>
2009, Hermann Vosseler <Ichthyostega@web.de>
Christian Thaeter <ct@pipapo.org>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as

View file

@ -40,11 +40,12 @@ using boost::regex;
using boost::smatch;
using boost::regex_search;
using util::noneg;
#include <iostream>
namespace util {
namespace lib {
/** create as a tokenised <i>copy</i> of the current commandline.
@ -88,4 +89,4 @@ namespace util {
} // namespace util
} // namespace lib

View file

@ -21,8 +21,8 @@
*/
#ifndef UTIL_CMDLINE_H
#define UTIL_CMDLINE_H
#ifndef LIB_CMDLINE_H
#define LIB_CMDLINE_H
#include <vector>
#include <string>
@ -30,7 +30,7 @@
namespace util {
namespace lib {
using std::string;
using std::vector;
@ -66,5 +66,5 @@ namespace util {
} // namespace util
} // namespace lib
#endif

View file

@ -33,7 +33,7 @@
predefined errors
*/
LUMIERA_ERROR_DEFINE (ERRNO, "errno");
LUMIERA_ERROR_DEFINE (EERROR, "could not initialize error system");
LUMIERA_ERROR_DEFINE (EERROR, "could not initialise error system");
LUMIERA_ERROR_DEFINE (UNKNOWN, "unknown error");
@ -78,7 +78,7 @@ lumiera_error_get (void)
LumieraErrorcontext self = pthread_getspecific (lumiera_error_tls);
if (!self)
{
/* malloc() and not lumiera_malloc() here because nothing else might be initialized when calling this */
/* malloc() and not lumiera_malloc() here because nothing else might be initialised when calling this */
self = malloc (sizeof *self);
if (!self)
LUMIERA_DIE (EERROR);

94
src/lib/searchpath.cpp Normal file
View file

@ -0,0 +1,94 @@
/*
Searchpath - helpers for searching directory lists and locating modules
Copyright (C) Lumiera.org
2011, Hermann Vosseler <Ichthyostega@web.de>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of
the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
* *****************************************************/
#include "lib/error.hpp"
#include "lib/searchpath.hpp"
#include "lib/symbol.hpp"
namespace lib {
LUMIERA_ERROR_DEFINE (FILE_NOT_DIRECTORY, "path element points at a file instead of a directory");
namespace {
Literal GET_PATH_TO_EXECUTABLE ("/proc/self/exe");
}
regex SearchPathSplitter::EXTRACT_PATHSPEC ("(\\$?ORIGIN/)?([^:]+)");
/** @internal helper to figure out the installation directory,
* as given by the absolute path of the currently executing program
* @warning this is Linux specific code */
string
findExePath()
{
static string buff(lib::STRING_MAX_RELEVANT+1, '\0' );
if (!buff[0])
{
ssize_t chars_read = readlink (GET_PATH_TO_EXECUTABLE, &buff[0], lib::STRING_MAX_RELEVANT);
if (0 > chars_read || chars_read == ssize_t(lib::STRING_MAX_RELEVANT))
throw error::Fatal ("unable to discover path of running executable");
buff.resize(chars_read);
}
return buff;
}
string
resolveModulePath (string moduleName, string searchPath)
{
fsys::path modulePathName (moduleName);
SearchPathSplitter searchLocation(searchPath);
while (true)
{
if (fsys::exists (modulePathName))
{
INFO (config, "found module %s", modulePathName.string().c_str());
return modulePathName.string();
}
// try / continue search path
if (searchLocation.isValid())
modulePathName = fsys::path() / searchLocation.fetch() / moduleName;
else
throw error::Config ("Module \""+moduleName+"\" not found"
+ (searchPath.empty()? ".":" in search path: "+searchPath));
} }
} // namespace lib

147
src/lib/searchpath.hpp Normal file
View file

@ -0,0 +1,147 @@
/*
SEARCHPATH.hpp - helpers for searching directory lists and locating modules
Copyright (C) Lumiera.org
2011, Hermann Vosseler <Ichthyostega@web.de>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of
the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef COMMON_SEARCHPATH_H
#define COMMON_SEARCHPATH_H
#include "lib/error.hpp"
#include "lib/bool-checkable.hpp"
#include <boost/program_options.hpp>
#include <boost/noncopyable.hpp>
#include <boost/filesystem.hpp>
#include <boost/regex.hpp>
#include <string>
namespace lib {
using std::string;
using boost::regex;
using boost::smatch;
using boost::regex_search;
using boost::sregex_iterator;
typedef smatch::value_type const& SubMatch;
namespace error = lumiera::error;
namespace fsys = boost::filesystem;
LUMIERA_ERROR_DECLARE (FILE_NOT_DIRECTORY); ///< path element points at a file instead of a directory
using error::LUMIERA_ERROR_ITER_EXHAUST;
/** retrieve the location of the executable */
string findExePath();
/**
* Helper: Access a path Specification as a sequence of filesystem Paths.
* This iterator class dissects a ':'-separated path list. The individual
* components may use the symbol \c $ORIGIN to denote the directory holding
* the current executable. After resolving this symbol, a valid absolute or
* relative filesystem path should result, which must not denote an existing
* file (directory is OK).
* @note #fetch picks the current component and advances the iteration.
*/
class SearchPathSplitter
: public BoolCheckable<SearchPathSplitter
, boost::noncopyable>
{
string pathSpec_;
sregex_iterator pos_,
end_;
static regex EXTRACT_PATHSPEC;
public:
SearchPathSplitter (string const& searchPath)
: pathSpec_(searchPath)
, pos_(pathSpec_.begin(),pathSpec_.end(), EXTRACT_PATHSPEC)
, end_()
{ }
bool
isValid() const
{
return pos_ != end_;
}
string
fetch ()
{
if (!isValid())
throw error::Logic ("Search path exhausted."
,LUMIERA_ERROR_ITER_EXHAUST);
string currentPathElement = resolveRelative();
++pos_;
return currentPathElement;
}
private:
/** maybe resolve a path spec given relative to
* the current Executable location ($ORIGIN) */
string
resolveRelative ()
{
if (containsORIGINToken())
return asAbsolutePath();
else
return getFullPath();
}
SubMatch found(int group=0) { return (*pos_)[group]; }
bool containsORIGINToken() { return found(1).matched; }
string getRelativePath() { return found(2); }
string getFullPath() { return found(); }
string
asAbsolutePath()
{
fsys::path exePathName (findExePath());
fsys::path modPathName (exePathName.remove_leaf() / getRelativePath());
if (fsys::exists(modPathName) && !fsys::is_directory (modPathName))
throw error::Invalid ("Error in search path: component \""+modPathName.string()+"\" is not a directory"
,LUMIERA_ERROR_FILE_NOT_DIRECTORY);
return modPathName.directory_string();
}
};
/** helper to establish the location to search for loadable modules.
* This is a simple demonstration of the basic technique used in the
* real application source to establish a plugin search path, based
* on the actual executable position plus compiled in and configured
* relative and absolute path specifications.
*/
string resolveModulePath (string moduleName, string searchPath = "");
} // namespace lib
#endif

View file

@ -232,7 +232,7 @@ namespace test {
void
Suite::describe ()
{
util::Cmdline noCmdline("");
lib::Cmdline noCmdline("");
PTestMap tests = testcases.getGroup(groupID_);
ASSERT (tests);

View file

@ -33,10 +33,9 @@ typedef boost::program_options::variables_map VarMap;
namespace op = boost::program_options;
using util::VectS;
using lib::VectS;
namespace test
{
namespace test {
/** set up an options parser to use the current commandline.
@ -47,7 +46,7 @@ namespace test
* --describe
* \endcode
*/
TestOption::TestOption (util::Cmdline& cmdline)
TestOption::TestOption (lib::Cmdline& cmdline)
: syntax("Run a collection of test cases. Supported parameters"),
parameters()
{
@ -89,37 +88,37 @@ namespace test
*/
const string
TestOption::getTestgroup ()
{
ASSERT (parameters.count ("group"));
return parameters["group"].as<string>();
}
{
ASSERT (parameters.count ("group"));
return parameters["group"].as<string>();
}
/** @return ID of a single test to run, empty string if not specified
*/
const string
TestOption::getTestID ()
{
if (parameters.count ("id") &&
parameters["id"].as<VectS>().size() > 0)
return parameters["id"].as<VectS>()[0];
else
return string ();
}
{
if (parameters.count ("id") &&
parameters["id"].as<VectS>().size() > 0)
return parameters["id"].as<VectS>()[0];
else
return string ();
}
/** @return \c true if --describe switch was given */
bool
TestOption::getDescribe ()
{
return parameters["describe"].as<bool>();
}
{
return parameters["describe"].as<bool>();
}
ostream&
operator<< (ostream& os, const TestOption& to)
{
return os << to.syntax;
}
{
return os << to.syntax;
}

View file

@ -53,7 +53,7 @@ namespace test {
class TestOption : private boost::noncopyable
{
public:
TestOption (util::Cmdline& cmdline);
TestOption (lib::Cmdline& cmdline);
const string getTestgroup ();
const string getTestID ();
bool getDescribe ();

View file

@ -34,7 +34,7 @@
#include "proc/facade.hpp"
#include "gui/guifacade.hpp"
using util::Cmdline;
using lib::Cmdline;
using lumiera::Subsys;
using lumiera::AppState;
using lumiera::ON_GLOBAL_INIT;

View file

@ -590,6 +590,21 @@ return: 0
END
TEST "Search path walking" SearchPathSplitter_test <<END
out-lit: ➢➢a
out-lit: ➢➢a
out-lit: ➢➢a
out-lit: ➢➢b
out-lit: ➢➢a
out-lit: ➢➢b
out-lit: ➢➢c
out: ➢➢.d.
out-lit: ➢➢ e f
out-lit: ➢➢/usr/bin
out-lit: ➢➢/usr/lib
END
TEST "Singleton_test" Singleton_test 23 <<END
out: testing TargetObj\(23\) as Singleton\(statically allocated\)
out: ctor TargetObj\(23\) successful

View file

@ -1,5 +1,5 @@
/*
Cmdlinewrapper(Test) - build vector of tokens from cmdline, various conversions
CmdlineWrapper(Test) - build vector of tokens from cmdline, various conversions
Copyright (C) Lumiera.org
2008, Hermann Vosseler <Ichthyostega@web.de>
@ -27,21 +27,26 @@
#include <iostream>
#include <sstream>
#include <string>
#include <boost/lambda/lambda.hpp>
using util::for_each;
using std::string;
using std::cout;
using std::endl;
namespace util {
namespace test {
namespace lib {
namespace test{
using boost::lambda::_1;
using boost::lambda::var;
/** @test for util::Cmdline, wrapping various example cmdlines */
/** @test for lib::Cmdline, wrapping various example cmdlines */
class CmdlineWrapper_test : public Test
{
void
@ -61,12 +66,12 @@ namespace test {
void
testLine (const string cmdline)
{
cout << "wrapping cmdline:" << cmdline << "..." << "\n";
cout << "wrapping cmdline:" << cmdline << "..." << endl;
int i=0;
Cmdline theCmdline (cmdline);
for_each(theCmdline, (cout << var(i)++ << "|" << _1 << "|\n"));
cout << "-->" << theCmdline << "\n";
cout << "-->" << theCmdline << endl;
// consistency checks
std::ostringstream output;
@ -88,12 +93,11 @@ namespace test {
{
const char* fakeArg[3] = {"CMD", "one ", "two"};
Cmdline theCmdline(3, fakeArg);
cout << "Standard Cmdlineformat:" << theCmdline << "\n";
cout << "Standard Cmdlineformat:" << theCmdline << endl;
}
};
LAUNCHER (CmdlineWrapper_test, "unit common");
}} // namespace util::test
}} // namespace lib::test

View file

@ -39,7 +39,7 @@ using lumiera::ON_GLOBAL_SHUTDOWN;
*/
int main (int argc, const char* argv[])
{
util::Cmdline args (argc,argv);
lib::Cmdline args (argc,argv);
test::TestOption optparser (args);
test::Suite suite (optparser.getTestgroup());
LifecycleHook::trigger (ON_GLOBAL_INIT);

View file

@ -33,7 +33,7 @@
#include <iostream>
using lumiera::Query;
using util::Cmdline;
using lib::Cmdline;
using util::isnil;
using util::contains;
using util::for_each;

View file

@ -0,0 +1,101 @@
/*
SearchPathSplitter(Test) - iterating a search path specification
Copyright (C) Lumiera.org
2011, Hermann Vosseler <Ichthyostega@web.de>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of
the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
* *****************************************************/
#include "lib/test/run.hpp"
#include "lib/test/test-helper.hpp"
#include "lib/searchpath.hpp"
#include "common/appstate.hpp"
#include <iostream>
using std::cout;
using std::endl;
namespace lib {
namespace test {
/******************************************************
* @test verify splitting a search path specification
* and retrieving the components by iteration.
* Embedded \c $ORIGIN tokens get resolved
* to the absolute path of this executable.
*/
class SearchPathSplitter_test : public Test
{
void
run (Arg)
{
walkSimplePaths ();
resolveEmbeddedOriginToken ();
}
void
walkSimplePaths ()
{
walk ("");
walk (":");
walk ("a:");
walk (":a");
walk ("a:b");
walk (":a:b:c:");
walk (" d : e f");
walk ("/usr/bin:/usr/lib");
SearchPathSplitter sp("");
VERIFY_ERROR (ITER_EXHAUST, sp.fetch() );
}
void
walk (string spec)
{
SearchPathSplitter path(spec);
while (path)
cout << "➢➢" << path.fetch() << endl;
}
void
resolveEmbeddedOriginToken ()
{
fsys::path exePath (findExePath());
string expected = (exePath.remove_leaf() / "modules").string();
SearchPathSplitter sp("xyz:$ORIGIN/modules:abc");
CHECK ("xyz" == sp.fetch());
CHECK (sp.fetch() == expected);
CHECK ("abc" == sp.fetch());
CHECK (!sp.isValid());
}
};
LAUNCHER (SearchPathSplitter_test, "unit common");
}} // namespace lib::test

View file

@ -69,7 +69,7 @@ namespace test {
const uint DELAY_FOR_FLOUNDERING_THRAD_ms = 20;
/** dummy options just to be ignored */
util::Cmdline dummyArgs ("");
lib::Cmdline dummyArgs ("");
lumiera::Option dummyOpt (dummyArgs);
/** marker for simulated failure exceptions */

View file

@ -26,12 +26,11 @@
#include "lib/test/testoption.hpp"
#include "lib/util.hpp"
using util::Cmdline;
using lib::Cmdline;
using util::isnil;
using std::endl;
namespace test
{
namespace test {
/****************************************************************
* invokes the TestOption parser for various example commandlines
@ -76,10 +75,10 @@ namespace test
void groupFilter2() { doIt (" --group TestGroupID SingleTestID "); }
void additionalCmd() { doIt (" --group TestGroupID SingleTestID spam eggs"); }
void additionalCmd2() { doIt ("\t\tSingleTestID spam --group TestGroupID \t --eggs"); }
};
LAUNCHER (TestOption_test, "function common");
LAUNCHER (TestOption_test, "function common");
} // namespace test