aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAvatar Ciaran McCreesh <ciaran.mccreesh@googlemail.com> 2007-02-26 01:40:18 +0000
committerAvatar Ciaran McCreesh <ciaran.mccreesh@googlemail.com> 2007-02-26 01:40:18 +0000
commite843055f3eabad2fcb273ffcadd6068bf96c0349 (patch)
treefbc9eec6c8c06a9d707b1ac3a35cb595bdc7a534
parent1bc2ebdda7f9fd6f5156e9883cb3754c54eaf8a4 (diff)
downloadpaludis-e843055f3eabad2fcb273ffcadd6068bf96c0349.tar.gz
paludis-e843055f3eabad2fcb273ffcadd6068bf96c0349.tar.xz
Start of dynamic environment loading
-rw-r--r--paludis/environment/Makefile.am26
-rw-r--r--paludis/environment/environment_maker.cc133
-rw-r--r--paludis/environment/environment_maker.hh107
-rw-r--r--paludis/repositories/repository_maker.cc5
-rw-r--r--paludis/repositories/repository_maker.hh16
-rw-r--r--paludis/repository.cc5
-rw-r--r--paludis/repository.hh16
7 files changed, 287 insertions, 21 deletions
diff --git a/paludis/environment/Makefile.am b/paludis/environment/Makefile.am
index bf57a32..8e2891c 100644
--- a/paludis/environment/Makefile.am
+++ b/paludis/environment/Makefile.am
@@ -6,3 +6,29 @@ MAINTAINERCLEANFILES = Makefile.in
built-sources : $(BUILT_SOURCES)
for s in `echo $(SUBDIRS) | tr -d .` ; do $(MAKE) -C $$s built-sources || exit 1 ; done
+lib_LTLIBRARIES = libpaludisenvironment.la
+
+paludis_environment_includedir = $(includedir)/paludis/environment/
+
+paludis_environment_include_HEADERS = \
+ environment_maker.hh
+
+libpaludisenvironment_la_SOURCES = \
+ environment_maker.cc \
+ $(paludis_environment_include_HEADERS)
+
+libpaludisenvironment_la_LDFLAGS = -version-info @VERSION_LIB_CURRENT@:@VERSION_LIB_REVISION@:0
+
+libpaludisenvironment_la_LIBADD = \
+ $(top_builddir)/paludis/util/libpaludisutil.la \
+ $(top_builddir)/paludis/libpaludis.la \
+ @DYNAMIC_LD_LIBS@
+
+AM_CXXFLAGS = -I$(top_srcdir) @PALUDIS_CXXFLAGS@
+DEFS= \
+ -DSYSCONFDIR=\"$(sysconfdir)\" \
+ -DLIBEXECDIR=\"$(libexecdir)\" \
+ -DDATADIR=\"$(datadir)\" \
+ -DLIBDIR=\"$(libdir)\"
+
+
diff --git a/paludis/environment/environment_maker.cc b/paludis/environment/environment_maker.cc
new file mode 100644
index 0000000..a984d35
--- /dev/null
+++ b/paludis/environment/environment_maker.cc
@@ -0,0 +1,133 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2007 Ciaran McCreesh <ciaranm@ciaranm.org>
+ *
+ * This file is part of the Paludis package manager. Paludis is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU General
+ * Public License version 2, as published by the Free Software Foundation.
+ *
+ * Paludis 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., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "environment_maker.hh"
+#include <paludis/util/fs_entry.hh>
+#include <paludis/util/dir_iterator.hh>
+#include <paludis/util/is_file_with_extension.hh>
+#include <paludis/util/system.hh>
+#include <paludis/about.hh>
+#include <list>
+#include <dlfcn.h>
+#include <stdint.h>
+
+using namespace paludis;
+
+NoSuchEnvironmentTypeError::NoSuchEnvironmentTypeError(const std::string & format) throw ():
+ ConfigurationError("No available maker for environment type '" + format + "'")
+{
+}
+
+PaludisEnvironmentSoDirNotADirectoryError::PaludisEnvironmentSoDirNotADirectoryError() throw () :
+ Exception("PALUDIS_ENVIRONMENT_SO_DIR not a directory")
+{
+}
+
+PaludisEnvironmentSoDirCannotDlopenError::PaludisEnvironmentSoDirCannotDlopenError(
+ const std::string & file, const std::string & e) throw () :
+ Exception("Cannot dlopen an environment .so file"),
+ _file(file),
+ _dlerr(e)
+{
+}
+
+PaludisEnvironmentSoDirCannotDlopenError::~PaludisEnvironmentSoDirCannotDlopenError() throw ()
+{
+}
+
+const char *
+PaludisEnvironmentSoDirCannotDlopenError::what() const throw ()
+{
+ if (_what.empty())
+ _what = std::string(Exception::what()) +
+ ": Cannot dlopen environment .so file '" + _file + "': '" + _dlerr + "'";
+ return _what.c_str();
+}
+
+namespace paludis
+{
+ template<>
+ struct Implementation<EnvironmentMaker>
+ {
+ std::list<void *> dl_opened;
+ };
+}
+
+void
+EnvironmentMaker::load_dir(const FSEntry & so_dir)
+{
+ for (DirIterator d(so_dir), d_end ; d != d_end ; ++d)
+ {
+ if (d->is_directory())
+ load_dir(*d);
+
+ if (! IsFileWithExtension(".so." + stringify(100 * PALUDIS_VERSION_MAJOR +
+ PALUDIS_VERSION_MINOR))(*d))
+ continue;
+
+ /* don't use RTLD_LOCAL, g++ is over happy about template instantiations, and it
+ * can lead to multiple singleton instances. */
+ void * dl(dlopen(stringify(*d).c_str(), RTLD_GLOBAL | RTLD_NOW));
+
+ if (dl)
+ {
+ _imp->dl_opened.push_back(dl);
+
+ void * reg(dlsym(dl, "register_environments"));
+ if (reg)
+ {
+ reinterpret_cast<void (*)(EnvironmentMaker *)>(
+ reinterpret_cast<uintptr_t>(reg))(this);
+ }
+ else
+ throw PaludisEnvironmentSoDirCannotDlopenError(stringify(*d),
+ "no register_environments function defined");
+ }
+ else
+ throw PaludisEnvironmentSoDirCannotDlopenError(stringify(*d), dlerror());
+ }
+
+ if ((so_dir / ".libs").is_directory())
+ load_dir(so_dir / ".libs");
+}
+
+EnvironmentMaker::EnvironmentMaker() :
+ PrivateImplementationPattern<EnvironmentMaker>(new Implementation<EnvironmentMaker>)
+{
+ FSEntry so_dir(getenv_with_default("PALUDIS_ENVIRONMENT_SO_DIR", LIBDIR "/paludis/environments"));
+
+ if (! so_dir.is_directory())
+ throw PaludisEnvironmentSoDirNotADirectoryError();
+
+ load_dir(so_dir);
+}
+
+EnvironmentMaker::~EnvironmentMaker()
+{
+}
+
+extern "C"
+{
+ void register_environments(EnvironmentMaker * maker);
+}
+
+void register_environments(EnvironmentMaker *)
+{
+}
+
diff --git a/paludis/environment/environment_maker.hh b/paludis/environment/environment_maker.hh
new file mode 100644
index 0000000..0be0688
--- /dev/null
+++ b/paludis/environment/environment_maker.hh
@@ -0,0 +1,107 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2007 Ciaran McCreesh <ciaranm@ciaranm.org>
+ *
+ * This file is part of the Paludis package manager. Paludis is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU General
+ * Public License version 2, as published by the Free Software Foundation.
+ *
+ * Paludis 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., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef PALUDIS_GUARD_PALUDIS_ENVIRONMENT_ENVIRONMENT_HH
+#define PALUDIS_GUARD_PALUDIS_ENVIRONMENT_ENVIRONMENT_HH 1
+
+#include <paludis/util/instantiation_policy.hh>
+#include <paludis/util/private_implementation_pattern.hh>
+#include <paludis/util/virtual_constructor.hh>
+#include <paludis/environment.hh>
+
+namespace paludis
+{
+ class FSEntry;
+
+ /**
+ * Thrown if an environment of the specified type does not exist.
+ *
+ * \ingroup grpexceptions
+ * \ingroup grpenvironment
+ * \nosubgrouping
+ */
+ class NoSuchEnvironmentTypeError : public ConfigurationError
+ {
+ public:
+ /**
+ * Constructor.
+ */
+ NoSuchEnvironmentTypeError(const std::string & format) throw ();
+ };
+
+ /**
+ * Thrown if PALUDIS_ENVIRONMENT_SO_DIR is not a directory.
+ *
+ * \ingroup grpexceptions
+ * \ingroup grprepository
+ */
+ class PALUDIS_VISIBLE PaludisEnvironmentSoDirNotADirectoryError :
+ public Exception
+ {
+ public:
+ PaludisEnvironmentSoDirNotADirectoryError() throw ();
+ };
+
+ /**
+ * Thrown if an environment .so cannot be used.
+ *
+ * \ingroup grpexceptions
+ * \ingroup grprepository
+ */
+ class PaludisEnvironmentSoDirCannotDlopenError :
+ public Exception
+ {
+ private:
+ std::string _file, _dlerr;
+ mutable std::string _what;
+
+ public:
+ PaludisEnvironmentSoDirCannotDlopenError(const std::string & file,
+ const std::string & e) throw ();
+
+ ~PaludisEnvironmentSoDirCannotDlopenError() throw ();
+
+ const char * what() const throw ();
+ };
+
+ /**
+ * Virtual constructor for environments.
+ *
+ * \ingroup grprepository
+ */
+ class PALUDIS_VISIBLE EnvironmentMaker :
+ public VirtualConstructor<std::string,
+ std::tr1::shared_ptr<Environment> (*) (const std::string &),
+ virtual_constructor_not_found::ThrowException<NoSuchEnvironmentTypeError> >,
+ public InstantiationPolicy<EnvironmentMaker, instantiation_method::SingletonTag>,
+ private PrivateImplementationPattern<EnvironmentMaker>
+ {
+ friend class InstantiationPolicy<EnvironmentMaker, instantiation_method::SingletonTag>;
+
+ private:
+ EnvironmentMaker();
+
+ void load_dir(const FSEntry &);
+
+ public:
+ ~EnvironmentMaker();
+ };
+}
+
+#endif
diff --git a/paludis/repositories/repository_maker.cc b/paludis/repositories/repository_maker.cc
index 868408b..d9623fe 100644
--- a/paludis/repositories/repository_maker.cc
+++ b/paludis/repositories/repository_maker.cc
@@ -38,6 +38,11 @@
using namespace paludis;
+NoSuchRepositoryTypeError::NoSuchRepositoryTypeError(const std::string & format) throw ():
+ ConfigurationError("No available maker for repository type '" + format + "'")
+{
+}
+
PaludisRepositorySoDirNotADirectoryError::PaludisRepositorySoDirNotADirectoryError() throw () :
Exception("PALUDIS_REPOSITORY_SO_DIR not a directory")
{
diff --git a/paludis/repositories/repository_maker.hh b/paludis/repositories/repository_maker.hh
index 725e017..5f3e447 100644
--- a/paludis/repositories/repository_maker.hh
+++ b/paludis/repositories/repository_maker.hh
@@ -30,6 +30,22 @@ namespace paludis
class FSEntry;
/**
+ * Thrown if a repository of the specified type does not exist.
+ *
+ * \ingroup grpexceptions
+ * \ingroup grprepository
+ * \nosubgrouping
+ */
+ class NoSuchRepositoryTypeError : public ConfigurationError
+ {
+ public:
+ /**
+ * Constructor.
+ */
+ NoSuchRepositoryTypeError(const std::string & format) throw ();
+ };
+
+ /**
* Thrown if PALUDIS_REPOSITORY_SO_DIR is not a directory.
*
* \ingroup grpexceptions
diff --git a/paludis/repository.cc b/paludis/repository.cc
index 4b39d9c..2a72f7d 100644
--- a/paludis/repository.cc
+++ b/paludis/repository.cc
@@ -88,11 +88,6 @@ Repository::name() const
return _name;
}
-NoSuchRepositoryTypeError::NoSuchRepositoryTypeError(const std::string & format) throw ():
- ConfigurationError("No available maker for repository type '" + format + "'")
-{
-}
-
PackageActionError::PackageActionError(const std::string & msg) throw () :
Exception(msg)
{
diff --git a/paludis/repository.hh b/paludis/repository.hh
index 869bd54..eeb148e 100644
--- a/paludis/repository.hh
+++ b/paludis/repository.hh
@@ -1183,22 +1183,6 @@ namespace paludis
};
/**
- * Thrown if a repository of the specified type does not exist.
- *
- * \ingroup grpexceptions
- * \ingroup grprepository
- * \nosubgrouping
- */
- class NoSuchRepositoryTypeError : public ConfigurationError
- {
- public:
- /**
- * Constructor.
- */
- NoSuchRepositoryTypeError(const std::string & format) throw ();
- };
-
- /**
* Parent class for install, uninstall errors.
*
* \ingroup grpexceptions