aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAvatar David Leverton <levertond@googlemail.com> 2007-05-17 19:10:44 +0000
committerAvatar David Leverton <levertond@googlemail.com> 2007-05-17 19:10:44 +0000
commitfa470788de490f721069b17c94a26b6d8571b7b2 (patch)
tree42702ddf46455d699d2d52321dcb5e713c2538a9
parentc37882eb4aa592435ba7847ebb8b7fe79f28d4f9 (diff)
downloadpaludis-fa470788de490f721069b17c94a26b6d8571b7b2.tar.gz
paludis-fa470788de490f721069b17c94a26b6d8571b7b2.tar.xz
.so hooks. Fixes: ticket:85
-rw-r--r--paludis/Makefile.am.m416
-rw-r--r--paludis/hook.cc9
-rw-r--r--paludis/hook.hh4
-rw-r--r--paludis/hooker.cc84
-rw-r--r--paludis/hooker_TEST.cc10
-rwxr-xr-xpaludis/hooker_TEST_setup.sh10
-rw-r--r--paludis/sohooks_TEST.cc78
7 files changed, 208 insertions, 3 deletions
diff --git a/paludis/Makefile.am.m4 b/paludis/Makefile.am.m4
index 07445d1..fe1c622 100644
--- a/paludis/Makefile.am.m4
+++ b/paludis/Makefile.am.m4
@@ -90,20 +90,33 @@ libpaludis_la_LDFLAGS = -version-info @VERSION_LIB_CURRENT@:@VERSION_LIB_REVISIO
libpaludismanpagethings_la_SOURCES = name.cc
+libpaludissohooks_TEST_la_SOURCES = sohooks_TEST.cc
+
+# -rpath to force shared library
+libpaludissohooks_TEST_la_LDFLAGS = -rpath /nowhere -version-info @VERSION_LIB_CURRENT@:@VERSION_LIB_REVISION@:0
+
+libpaludissohooks_TEST_la_LIBADD = $(top_builddir)/paludis/libpaludis.la
+
if ! MONOLITHIC
libpaludis_la_LIBADD = \
- $(top_builddir)/paludis/util/libpaludisutil.la
+ $(top_builddir)/paludis/util/libpaludisutil.la \
+ @DYNAMIC_LD_LIBS@
libpaludismanpagethings_la_LIBADD = \
$(top_builddir)/paludis/util/libpaludisutil.la
+else
+
+libpaludis_la_LIBADD = @DYNAMIC_LD_LIBS@
+
endif
TESTS = testlist
check_PROGRAMS = $(TESTS)
check_SCRIPTS = testscriptlist
+check_LTLIBRARIES = libpaludissohooks_TEST.la
paludis_datadir = $(datadir)/paludis
paludis_data_DATA = repository_blacklist.txt
@@ -148,5 +161,6 @@ TESTS_ENVIRONMENT = env \
PALUDIS_SKIP_CONFIG="yes" \
PALUDIS_REPOSITORY_SO_DIR="$(top_builddir)/paludis/repositories" \
TEST_SCRIPT_DIR="$(srcdir)/" \
+ SO_SUFFIX=@VERSION_LIB_CURRENT@ \
bash $(top_srcdir)/test/run_test.sh
diff --git a/paludis/hook.cc b/paludis/hook.cc
index 13bdff7..0591952 100644
--- a/paludis/hook.cc
+++ b/paludis/hook.cc
@@ -71,6 +71,15 @@ Hook::operator() (const std::string & k, const std::string & v) const
return result;
}
+std::string
+Hook::get(const std::string & k) const
+{
+ if (_imp->extra_env.end() != _imp->extra_env.find(k))
+ return _imp->extra_env.at(k);
+ else
+ return std::string("");
+}
+
Hook
Hook::grab_output(const AllowedOutputValues & av)
{
diff --git a/paludis/hook.hh b/paludis/hook.hh
index ef8f44c..d4395c0 100644
--- a/paludis/hook.hh
+++ b/paludis/hook.hh
@@ -62,6 +62,10 @@ namespace paludis
Hook operator() (const std::string & key, const std::string & value) const
PALUDIS_ATTRIBUTE((warn_unused_result));
+ /// Get data from the hook.
+ std::string get(const std::string & key) const
+ PALUDIS_ATTRIBUTE((warn_unused_result));
+
Hook grab_output(const AllowedOutputValues & av);
bool validate_value(const std::string & value) const;
diff --git a/paludis/hooker.cc b/paludis/hooker.cc
index 49973cb..86ff5cf 100644
--- a/paludis/hooker.cc
+++ b/paludis/hooker.cc
@@ -34,8 +34,10 @@
#include <paludis/util/graph-impl.hh>
#include <paludis/util/pstream.hh>
#include <paludis/util/tokeniser.hh>
+#include <paludis/about.hh>
#include <list>
#include <iterator>
+#include <dlfcn.h>
using namespace paludis;
@@ -111,6 +113,30 @@ namespace
virtual void add_dependencies(const Hook &, DirectedGraph<std::string, int> &);
};
+
+ class SoHookFile :
+ public HookFile
+ {
+ private:
+ const FSEntry _file_name;
+ const Environment * const _env;
+
+ void * _dl;
+ HookResult (*_run)(Environment const *, const Hook &);
+ void (*_add_dependencies)(Environment const *, const Hook &, DirectedGraph<std::string, int> &);
+
+ public:
+ SoHookFile(const FSEntry &, const bool, const Environment * const);
+
+ virtual HookResult run(const Hook &) const PALUDIS_ATTRIBUTE((warn_unused_result));
+
+ virtual const FSEntry file_name() const
+ {
+ return _file_name;
+ }
+
+ virtual void add_dependencies(const Hook &, DirectedGraph<std::string, int> &);
+ };
}
HookResult
@@ -279,6 +305,55 @@ FancyHookFile::_add_dependency_class(const Hook & hook, DirectedGraph<std::strin
+ "' returned failure '" + stringify(exit_status) + "'");
}
+SoHookFile::SoHookFile(const FSEntry & f, const bool, const Environment * const e) :
+ _file_name(f),
+ _env(e),
+ _dl(0),
+ _run(0),
+ _add_dependencies(0)
+{
+ /* don't use RTLD_LOCAL, g++ is over happy about template instantiations, and it
+ * can lead to multiple singleton instances. */
+ _dl = dlopen(stringify(f).c_str(), RTLD_GLOBAL | RTLD_NOW);
+
+ if (_dl)
+ {
+ _run = reinterpret_cast<HookResult (*)(
+ Environment const *, const Hook &)>(
+ reinterpret_cast<uintptr_t>(dlsym(_dl, "paludis_hook_run")));
+
+ if (! _run)
+ Log::get_instance()->message(ll_warning, lc_no_context, ".so hook '" + stringify(f) + "' does not define the paludis_hook_run function");
+
+ _add_dependencies = reinterpret_cast<void (*)(
+ Environment const *, const Hook &, DirectedGraph<std::string, int> &)>(
+ reinterpret_cast<uintptr_t>(dlsym(_dl, "paludis_hook_add_dependencies")));
+ }
+ else
+ Log::get_instance()->message(ll_warning, lc_no_context, "Opening .so hook '" + stringify(f) + "' failed: " + dlerror());
+}
+
+HookResult
+SoHookFile::run(const Hook & hook) const
+{
+ Context c("When running .so hook '" + stringify(file_name()) + "' for hook '" + hook.name() + "':");
+
+ if (! _run)
+ return HookResult(0, "");
+
+ Log::get_instance()->message(ll_debug, lc_no_context, "Starting .so hook '" +
+ stringify(file_name()) + "' for '" + hook.name() + "'");
+
+ return _run(_env, hook);
+}
+
+void
+SoHookFile::add_dependencies(const Hook & hook, DirectedGraph<std::string, int> & g)
+{
+ if (_add_dependencies)
+ _add_dependencies(_env, hook, g);
+}
+
namespace paludis
{
template<>
@@ -394,6 +469,15 @@ Hooker::perform_hook(const Hook & hook) const
Log::get_instance()->message(ll_warning, lc_context, "Discarding hook file '" + stringify(*e)
+ "' because of naming conflict with '" + stringify(
hook_files.find(stringify(strip_trailing_string(e->basename(), ".hook")))->second->file_name()) + "'");
+
+ std::string so_suffix(".so." + stringify(100 * PALUDIS_VERSION_MAJOR + PALUDIS_VERSION_MINOR));
+ if (is_file_with_extension(*e, so_suffix, IsFileWithOptions()))
+ if (! hook_files.insert(std::make_pair(strip_trailing_string(e->basename(), so_suffix),
+ std::tr1::shared_ptr<HookFile>(new SoHookFile(*e, d->second, _imp->env)))).second)
+ Log::get_instance()->message(ll_warning, lc_context, "Discarding hook file '" + stringify(*e)
+ + "' because of naming conflict with '" + stringify(
+ hook_files.find(stringify(strip_trailing_string(e->basename(), so_suffix)))->second->file_name()) + "'");
+
}
}
diff --git a/paludis/hooker_TEST.cc b/paludis/hooker_TEST.cc
index 92e05ab..a46bbf9 100644
--- a/paludis/hooker_TEST.cc
+++ b/paludis/hooker_TEST.cc
@@ -47,6 +47,9 @@ namespace test_cases
result = hooker.perform_hook(Hook("fancy_hook"));
TEST_CHECK_EQUAL(result.max_exit_status, 5);
TEST_CHECK_EQUAL(result.output, "");
+ result = hooker.perform_hook(Hook("so_hook"));
+ TEST_CHECK_EQUAL(result.max_exit_status, 6);
+ TEST_CHECK_EQUAL(result.output, "");
result = hooker.perform_hook(Hook("several_hooks"));
TEST_CHECK_EQUAL(result.max_exit_status, 7);
TEST_CHECK_EQUAL(result.output, "");
@@ -73,7 +76,7 @@ namespace test_cases
std::ifstream f(stringify(FSEntry("hooker_TEST_dir/ordering.out")).c_str());
std::string line((std::istreambuf_iterator<char>(f)), std::istreambuf_iterator<char>());
- TEST_CHECK_EQUAL(line, "e\nc\nf\nd\nb\na\ng\ni\nh\nk\nj\n");
+ TEST_CHECK_EQUAL(line, "e\nc\nf\nd\nb\na\ng\ni\nh\nsohook\nk\nj\n");
}
} test_hooker_ordering;
@@ -147,6 +150,11 @@ namespace test_cases
TEST_CHECK_EQUAL(result.max_exit_status, 0);
TEST_CHECK_EQUAL(result.output, "foo");
+ result = hooker.perform_hook(Hook("so_hook_output")
+ .grab_output(Hook::AllowedOutputValues()("foo")));
+ TEST_CHECK_EQUAL(result.max_exit_status, 0);
+ TEST_CHECK_EQUAL(result.output, "foo");
+
result = hooker.perform_hook(Hook("several_hooks_output")
.grab_output(Hook::AllowedOutputValues()));
TEST_CHECK_EQUAL(result.max_exit_status, 0);
diff --git a/paludis/hooker_TEST_setup.sh b/paludis/hooker_TEST_setup.sh
index 689da3f..ec5338d 100755
--- a/paludis/hooker_TEST_setup.sh
+++ b/paludis/hooker_TEST_setup.sh
@@ -50,6 +50,13 @@ END
chmod +x fancy_hook_output/one.hook
+mkdir so_hook
+ln -s ../../.libs/libpaludissohooks_TEST.so.${SO_SUFFIX} so_hook
+
+mkdir so_hook_output
+ln -s ../../.libs/libpaludissohooks_TEST.so.${SO_SUFFIX} so_hook_output
+
+
mkdir several_hooks
cat <<"END" > several_hooks/one.hook
hook_run_several_hooks() {
@@ -194,7 +201,7 @@ hook_after_ordering() {
echo i
;;
j)
- echo k
+ echo k libpaludissohooks_TEST
;;
esac
}
@@ -204,6 +211,7 @@ chmod +x ordering.common
for a in a b c d e f g h i j k ; do
ln -s ../ordering.common ordering/${a}.hook
done
+ln -s ../../.libs/libpaludissohooks_TEST.so.${SO_SUFFIX} ordering
mkdir bad_hooks
cat <<"END" > bad_hooks.common
diff --git a/paludis/sohooks_TEST.cc b/paludis/sohooks_TEST.cc
new file mode 100644
index 0000000..b136444
--- /dev/null
+++ b/paludis/sohooks_TEST.cc
@@ -0,0 +1,78 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2007 David Leverton <u01drl3@abdn.ac.uk>
+ *
+ * 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 <paludis/environment.hh>
+#include <paludis/hook.hh>
+#include <paludis/util/graph.hh>
+#include <iostream>
+#include <fstream>
+
+using namespace paludis;
+
+namespace
+{
+ HookResult
+ so_hook_run(const Environment *, const Hook &)
+ {
+ return HookResult(6, "");
+ }
+
+ HookResult
+ so_hook_output_run(const Environment *, const Hook &)
+ {
+ return HookResult(0, "foo");
+ }
+
+ HookResult
+ ordering_run(const Environment *, const Hook &)
+ {
+ std::ofstream f("hooker_TEST_dir/ordering.out", std::ios_base::app);
+ f << "sohook" << std::endl;
+ return HookResult(0, "");
+ }
+
+ void
+ ordering_add_dependencies(const Environment *, const Hook &,
+ DirectedGraph<std::string, int> & graph)
+ {
+ graph.add_edge("k", "libpaludissohooks_TEST", 0);
+ }
+}
+
+extern "C" HookResult PALUDIS_VISIBLE
+paludis_hook_run(const Environment * env, const Hook & hook)
+{
+ if ("so_hook" == hook.name())
+ return so_hook_run(env, hook);
+ if ("so_hook_output" == hook.name())
+ return so_hook_output_run(env, hook);
+ if ("ordering" == hook.name())
+ return ordering_run(env, hook);
+
+ return HookResult(0, "");
+}
+
+extern "C" void PALUDIS_VISIBLE
+paludis_hook_add_dependencies(const Environment * env, const Hook & hook,
+ DirectedGraph<std::string, int> & graph)
+{
+ if ("ordering" == hook.name())
+ ordering_add_dependencies(env, hook, graph);
+}
+