aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAvatar Ciaran McCreesh <ciaran.mccreesh@googlemail.com> 2008-03-22 15:59:52 +0000
committerAvatar Ciaran McCreesh <ciaran.mccreesh@googlemail.com> 2008-03-22 15:59:52 +0000
commit0a479e1fc25255d60b573ba7b91295ff7b1bf080 (patch)
tree2d252ffe335bc70695701c2d2e0a04ba91868403
parentef30feada12c02381e32b649b132e6a6c5efaf25 (diff)
downloadpaludis-0a479e1fc25255d60b573ba7b91295ff7b1bf080.tar.gz
paludis-0a479e1fc25255d60b573ba7b91295ff7b1bf080.tar.xz
Implement auto hooks, new install_task hook phases. Fixes: ticket:434, ticket:435, ticket:502
-rw-r--r--NEWS6
-rw-r--r--doc/configuration/hooks.html.part44
-rw-r--r--hooks/Makefile.am.m417
-rw-r--r--hooks/demos/elog.bash.in10
-rwxr-xr-xhooks/find_config_updates.hook24
-rwxr-xr-xhooks/news.hook20
-rw-r--r--paludis/hook.hh7
-rw-r--r--paludis/hooker.cc440
-rw-r--r--paludis/hooker.hh8
-rw-r--r--paludis/install_task.cc21
-rw-r--r--paludis/python_hooks.cc8
11 files changed, 427 insertions, 178 deletions
diff --git a/NEWS b/NEWS
index 75a7553..0665f38 100644
--- a/NEWS
+++ b/NEWS
@@ -13,6 +13,12 @@ trunk/:
* importare now has an --install-under option.
+ * Added two new hook phases, install_task_execute_pre and
+ install_task_execute_post, to avoid issues with continue-on-failure.
+
+ * Hooks in the auto/ directory can now specify in which phase or phases they
+ are to be run.
+
0.26.0_alpha12:
* The merger is able to detect hardlinks and tries to merge them as such.
diff --git a/doc/configuration/hooks.html.part b/doc/configuration/hooks.html.part
index 504a9f8..63aa7be 100644
--- a/doc/configuration/hooks.html.part
+++ b/doc/configuration/hooks.html.part
@@ -118,6 +118,8 @@ hooks.</p>
<li><code>install_pretend_post</code></li>
<li><code>install_pretend_display_item_pre</code></li>
<li><code>install_pretend_display_item_post</code></li>
+ <li><code>install_task_execute_pre</code></li>
+ <li><code>install_task_execute_post</code></li>
<li><code>uninstall_pre</code></li>
<li><code>uninstall_fail</code></li>
<li><code>uninstall_post</code></li>
@@ -139,12 +141,20 @@ hooks.</p>
<li><code>fetch_all_post</code></li>
</ul>
-<p>In general, certain special environment variables will be set. <code>HOOK</code> will contain
-the name of the hook. For <code>all</code> hooks, <code>TARGETS</code> will contain the targets
-for the operation. For non-<code>all</code> hooks, <code>TARGET</code> will contain the current
-target. The <code>PALUDIS_CMDLINE</code> variables described below are also available. For the
-<code>install_pretend_display_item</code> hooks, the <code>KIND</code> variable will also be of
-interest.</p>
+<p>In general, certain special environment variables will be set:</p>
+
+<ul>
+ <li><code>HOOK</code> will contain the name of the hook.</li>
+ <li>For <code>all</code> hooks, <code>TARGETS</code> will contain the targets
+ for the operation.</li>
+ <li>For non-<code>all</code> hooks, <code>TARGET</code> will contain the current
+ target.</li>
+ <li>The <code>PALUDIS_CMDLINE</code> variables described below are also available.
+ <li>For the <code>install_pretend_display_item</code> hooks, the <code>KIND</code> variable will also be of
+ interest.</li>
+ <li>For the <code>install_task_execute_pre</code> and <code>install_task_execute_post</code> hooks,
+ <code>PRETEND</code>, <code>FETCH_ONLY</code> and <code>SUCCESS</code> may be useful.</li>
+</ul>
<h3 id="ebuild-phase-hooks">Ebuild Phase Hooks</h3>
@@ -314,6 +324,10 @@ scripts should be executable (<code>chmod a+x</code>). They can live in three lo
systems, <code><em>LIBDIR</em></code> is <code>/usr/lib</code> or <code>/usr/lib64</code>.</li>
</ul>
+<p>For <code>.hook</code> and <code>.so</code> hooks, rather than using <code><em>hookname</em></code>, the
+<code>auto</code> directory may be used. In this case, Paludis will ask the hook for which hook names it should be
+run.</p>
+
<h3 id="bash-hooks">Bash Hooks</h3>
<p>A <code>.bash</code> hook is merely executed when the associated action is
@@ -364,9 +378,17 @@ hook_after_install_all_post()
}
</pre>
-<p>Note that the <code>hook_depend_</code> and <code>hook_after_</code> functions
-are cached, and are generally only called once per session, so the output should
-not vary based upon outside parameters.</p>
+<p>If the hook is located in an <code>auto</code> directory, the <code>hook_auto_names</code> function must also be
+provided. This function should output the hook names under which the hook should be run. For example:</p>
+
+<pre>
+hook_auto_names() {
+ echo install_all_pre install_all_post
+}
+</pre>
+
+<p>Note that the <code>hook_depend_</code>, <code>hook_after_</code> and <code>hook_auto_names</code> functions are
+cached, and are generally only called once per session, so the output should not vary based upon outside parameters.</p>
<h3 id="py-hooks">Python Hooks</h3>
@@ -411,7 +433,9 @@ or 102 for Paludis 1.2.y). The library must export a function with prototype
that performs the action, and optionally one with prototype
<code>void paludis_hook_add_dependencies(const paludis::Environment *, const paludis::Hook &amp;,
paludis::DirectedGraph&lt;std::string, int&gt; &amp;)</code>
-if it needs to define ordering dependencies with other hooks. Both functions are
+if it needs to define ordering dependencies with other hooks. If the hook is to be placed in an <code>auto</code>
+directory, it must also define <code>const paludis::tr1::shared_ptr&lt;const Seqyence&lt;std::string&gt; &gt;
+paludis_hook_auto_phases(const paludis::Environment *)</code>. All functions are
declared in the header <code>&lt;paludis/hook.hh&gt;</code>, including any necessary
<code>extern</code> or visibility declarations.</p>
diff --git a/hooks/Makefile.am.m4 b/hooks/Makefile.am.m4
index e7bfda0..2651211 100644
--- a/hooks/Makefile.am.m4
+++ b/hooks/Makefile.am.m4
@@ -10,19 +10,19 @@ SUBDIRS = . demos
installvarlibpaludisnewsdir = $(localstatedir)/gentoo/news
installhookcommonprogdir = $(libexecdir)/paludis/hooks/common
-installhookinstallallpostdir = $(libexecdir)/paludis/hooks/install_all_post
+installhookautoprogdir = $(libexecdir)/paludis/hooks/auto
installhookinstallpostdir = $(libexecdir)/paludis/hooks/install_post
installhookcommonprog_SCRIPTS = \
gnu_info_index.bash \
eselect_env_update.bash \
log.bash \
- news.hook \
installable_cache_regen.bash \
installed_cache_regen.bash \
write_cache_clean.bash
-installhookinstallallpost_SCRIPTS = \
+installhookautoprog_SCRIPTS = \
+ news.hook \
find_config_updates.hook
installhookinstallpost_SCRIPTS = \
@@ -44,7 +44,7 @@ check_PROGRAMS =
EXTRA_DIST = \
Makefile.am.m4 \
$(installhookcommonprog_SCRIPTS) \
- $(installhookinstallallpost_SCRIPTS) \
+ $(installhookautoprog_SCRIPTS) \
$(installhookinstallpost_SCRIPTS) \
$(check_SCRIPTS)
@@ -57,6 +57,7 @@ installuserhooks$1_DATA = .keep
installuserhooksplat$1dir = $(libdir)/paludis/hooks/$1
installuserhooksplat$1_DATA = .keep')
+userhook(`auto')
userhook(`install_pre')
userhook(`install_fail')
userhook(`install_post')
@@ -66,6 +67,8 @@ userhook(`install_pretend_pre')
userhook(`install_pretend_post')
userhook(`install_pretend_display_item_pre')
userhook(`install_pretend_display_item_post')
+userhook(`install_task_execute_pre')
+userhook(`install_task_execute_post')
userhook(`clean_all_post')
userhook(`clean_all_pre')
userhook(`clean_fail')
@@ -179,6 +182,7 @@ define(`systemhook', `
installsystemhooks$1dir = $(libexecdir)/paludis/hooks/$1
installsystemhooks$1_DATA = .keep')
+systemhook(`auto')
systemhook(`install_pre')
systemhook(`install_post')
systemhook(`install_all_pre')
@@ -221,6 +225,7 @@ install-data-local :
install -d $(DESTDIR)/$(libexecdir)/paludis/hooks/fetch_all_post/
install -d $(DESTDIR)/$(libexecdir)/paludis/hooks/fetch_pre/
install -d $(DESTDIR)/$(libexecdir)/paludis/hooks/fetch_post/
+ install -d $(DESTDIR)/$(libexecdir)/paludis/hooks/install_task_execute_post/
ln -sf ../common/gnu_info_index.bash $(DESTDIR)/$(libexecdir)/paludis/hooks/uninstall_all_post/
ln -sf ../common/gnu_info_index.bash $(DESTDIR)/$(libexecdir)/paludis/hooks/install_all_post/
ln -sf ../common/eselect_env_update.bash $(DESTDIR)/$(libexecdir)/paludis/hooks/uninstall_all_post/
@@ -243,9 +248,6 @@ install-data-local :
ln -sf ../common/log.bash $(DESTDIR)/$(libexecdir)/paludis/hooks/uninstall_post/
ln -sf ../common/log.bash $(DESTDIR)/$(libexecdir)/paludis/hooks/sync_pre/
ln -sf ../common/log.bash $(DESTDIR)/$(libexecdir)/paludis/hooks/sync_post/
- ln -sf ../common/news.hook $(DESTDIR)/$(libexecdir)/paludis/hooks/sync_all_post/
- ln -sf ../common/news.hook $(DESTDIR)/$(libexecdir)/paludis/hooks/install_all_post/
- ln -sf ../common/news.hook $(DESTDIR)/$(libexecdir)/paludis/hooks/install_pretend_post/
ln -sf ../common/installable_cache_regen.bash $(DESTDIR)/$(libexecdir)/paludis/hooks/sync_all_post/
ln -sf ../common/write_cache_clean.bash $(DESTDIR)/$(libexecdir)/paludis/hooks/sync_all_post/
ln -sf ../common/installed_cache_regen.bash $(DESTDIR)/$(libexecdir)/paludis/hooks/install_post/
@@ -256,7 +258,6 @@ uninstall-local :
rm -f $(DESTDIR)/$(libexecdir)/paludis/hooks/*/gnu_info_index.bash
rm -f $(DESTDIR)/$(libexecdir)/paludis/hooks/*/eselect_env_update.bash
rm -f $(DESTDIR)/$(libexecdir)/paludis/hooks/*/log.bash
- rm -f $(DESTDIR)/$(libexecdir)/paludis/hooks/*/news.hook
rm -f $(DESTDIR)/$(libexecdir)/paludis/hooks/*/write_cache_clean.bash
Makefile.am : Makefile.am.m4
diff --git a/hooks/demos/elog.bash.in b/hooks/demos/elog.bash.in
index 6e1598a..fa66545 100644
--- a/hooks/demos/elog.bash.in
+++ b/hooks/demos/elog.bash.in
@@ -6,13 +6,7 @@
# this functionality, this script should be copied or symlinked into:
#
# @DATADIR@/paludis/hooks/elog/
-# @DATADIR@/paludis/hooks/install_all_pre/
-# @DATADIR@/paludis/hooks/install_all_post/
-# @DATADIR@/paludis/hooks/install_fail/
-# @DATADIR@/paludis/hooks/uninstall_all_pre/
-# @DATADIR@/paludis/hooks/uninstall_all_post/
-# @DATADIR@/paludis/hooks/uninstall_fail/
-# @DATADIR@/paludis/hooks/clean_fail/
+# @DATADIR@/paludis/hooks/install_task_execute_post/
#
# And optionally:
#
@@ -56,7 +50,7 @@ case "${HOOK}" in
fi
;;
- install_all_post|uninstall_all_post|install_fail|uninstall_fail|clean_fail)
+ install_all_post|uninstall_all_post|install_fail|uninstall_fail|clean_fail|install_task_execute_post)
echo
old_pf=""
while read line ; do
diff --git a/hooks/find_config_updates.hook b/hooks/find_config_updates.hook
index da5156b..8122a0f 100755
--- a/hooks/find_config_updates.hook
+++ b/hooks/find_config_updates.hook
@@ -18,6 +18,10 @@
check_for_config_updates()
{
+ if [[ "${PRETEND}" == true ]] ; then
+ return
+ fi
+
shopt -s extglob
export PATH="$(${PALUDIS_EBUILD_DIR}/utils/canonicalise ${PALUDIS_EBUILD_DIR}/utils/ ):${PATH}"
@@ -57,8 +61,26 @@ check_for_config_updates()
fi
}
-for h in install_all_post ; do
+stale_hook()
+{
+ export PATH="$(${PALUDIS_EBUILD_DIR}/utils/canonicalise ${PALUDIS_EBUILD_DIR}/utils/ ):${PATH}"
+ source ${PALUDIS_ECHO_FUNCTIONS_DIR:-${PALUDIS_EBUILD_DIR}}/echo_functions.bash
+
+ echo
+ ewarn "find_config_updates hook should not be run in phase '${HOOK}'"
+ ewarn "Do you have stale symlinks?"
+}
+
+for h in install_task_execute_post ; do
eval "hook_run_${h}() { check_for_config_updates ; }"
eval "hook_after_${h}() { echo log write_cache_clean news ; }"
done
+for h in install_all_post ; do
+ eval "hook_run_${h}() { stale_hook ; }"
+done
+
+hook_auto_names() {
+ echo install_task_execute_post
+}
+
diff --git a/hooks/news.hook b/hooks/news.hook
index 7cb396b..db4975e 100755
--- a/hooks/news.hook
+++ b/hooks/news.hook
@@ -33,8 +33,26 @@ check_for_news()
fi
}
-for h in sync_all_post install_all_post install_pretend_post ; do
+stale_hook()
+{
+ export PATH="$(${PALUDIS_EBUILD_DIR}/utils/canonicalise ${PALUDIS_EBUILD_DIR}/utils/ ):${PATH}"
+ source ${PALUDIS_ECHO_FUNCTIONS_DIR:-${PALUDIS_EBUILD_DIR}}/echo_functions.bash
+
+ echo
+ ewarn "news hook should not be run in phase '${HOOK}'"
+ ewarn "Do you have stale symlinks?"
+}
+
+for h in sync_all_post install_all_post install_pretend_post install_task_execute_post ; do
eval "hook_run_${h}() { check_for_news ; }"
eval "hook_after_${h}() { echo gnu_info_index eselect_env_update log write_cache_clean ; }"
done
+for h in install_all_post install_pretend_post ; do
+ eval "hook_run_${h}() { stale_hook ; }"
+done
+
+hook_auto_names() {
+ echo sync_all_post install_task_execute_post
+}
+
diff --git a/paludis/hook.hh b/paludis/hook.hh
index e06a2af..365dc77 100644
--- a/paludis/hook.hh
+++ b/paludis/hook.hh
@@ -1,7 +1,7 @@
/* vim: set sw=4 sts=4 et foldmethod=syntax : */
/*
- * Copyright (c) 2005, 2006, 2007 Ciaran McCreesh
+ * Copyright (c) 2005, 2006, 2007, 2008 Ciaran McCreesh
* Copyright (c) 2007 Piotr JaroszyƄski
*
* This file is part of the Paludis package manager. Paludis is free software;
@@ -28,6 +28,8 @@
#include <paludis/util/private_implementation_pattern.hh>
#include <paludis/util/operators.hh>
#include <paludis/util/wrapped_forward_iterator-fwd.hh>
+#include <paludis/util/tr1_memory.hh>
+#include <paludis/util/sequence-fwd.hh>
#include <string>
@@ -140,4 +142,7 @@ extern "C" paludis::HookResult PALUDIS_VISIBLE paludis_hook_run(
extern "C" void PALUDIS_VISIBLE paludis_hook_add_dependencies(
const paludis::Environment *, const paludis::Hook &, paludis::DirectedGraph<std::string, int> &);
+extern "C" const paludis::tr1::shared_ptr<const paludis::Sequence<std::string> > PALUDIS_VISIBLE paludis_hook_auto_phases(
+ const paludis::Environment *);
+
#endif
diff --git a/paludis/hooker.cc b/paludis/hooker.cc
index 2f3e2aa..b84c0ea 100644
--- a/paludis/hooker.cc
+++ b/paludis/hooker.cc
@@ -34,6 +34,9 @@
#include <paludis/util/graph-impl.hh>
#include <paludis/util/tokeniser.hh>
#include <paludis/util/mutex.hh>
+#include <paludis/util/sequence-impl.hh>
+#include <paludis/util/make_shared_ptr.hh>
+#include <paludis/util/join.hh>
#include <paludis/about.hh>
#include <list>
#include <iterator>
@@ -41,12 +44,16 @@
using namespace paludis;
+template class Sequence<tr1::shared_ptr<HookFile> >;
+
HookFile::~HookFile()
{
}
namespace
{
+ static const std::string so_suffix(".so." + stringify(100 * PALUDIS_VERSION_MAJOR + PALUDIS_VERSION_MINOR));
+
class BashHookFile :
public HookFile
{
@@ -73,6 +80,11 @@ namespace
virtual void add_dependencies(const Hook &, DirectedGraph<std::string, int> &)
{
}
+
+ virtual const tr1::shared_ptr<const Sequence<std::string> > auto_hook_names() const
+ {
+ return make_shared_ptr(new Sequence<std::string>);
+ }
};
class FancyHookFile :
@@ -101,6 +113,8 @@ namespace
}
virtual void add_dependencies(const Hook &, DirectedGraph<std::string, int> &);
+
+ virtual const tr1::shared_ptr<const Sequence<std::string> > auto_hook_names() const;
};
class SoHookFile :
@@ -111,8 +125,9 @@ namespace
const Environment * const _env;
void * _dl;
- HookResult (*_run)(Environment const *, const Hook &);
- void (*_add_dependencies)(Environment const *, const Hook &, DirectedGraph<std::string, int> &);
+ HookResult (*_run)(const Environment *, const Hook &);
+ void (*_add_dependencies)(const Environment *, const Hook &, DirectedGraph<std::string, int> &);
+ const tr1::shared_ptr<const Sequence<std::string > > (*_auto_hook_names)(const Environment *);
public:
SoHookFile(const FSEntry &, const bool, const Environment * const);
@@ -125,6 +140,8 @@ namespace
}
virtual void add_dependencies(const Hook &, DirectedGraph<std::string, int> &);
+
+ virtual const tr1::shared_ptr<const Sequence<std::string> > auto_hook_names() const;
};
}
@@ -228,6 +245,52 @@ FancyHookFile::run(const Hook & hook) const
return HookResult(exit_status, output);
}
+const tr1::shared_ptr<const Sequence<std::string > >
+FancyHookFile::auto_hook_names() const
+{
+ Context c("When querying auto hook names for fancy hook '" + stringify(file_name()) + "':");
+
+ Log::get_instance()->message(ll_debug, lc_no_context) << "Starting hook script '" <<
+ file_name() << "' for auto hook names";
+
+ Command cmd(getenv_with_default("PALUDIS_HOOKER_DIR", LIBEXECDIR "/paludis") +
+ "/hooker.bash '" + stringify(file_name()) + "' 'hook_auto_names'");
+
+ cmd
+ .with_setenv("ROOT", stringify(_env->root()))
+ .with_setenv("HOOK_FILE", stringify(file_name()))
+ .with_setenv("HOOK_LOG_LEVEL", stringify(Log::get_instance()->log_level()))
+ .with_setenv("PALUDIS_EBUILD_DIR", getenv_with_default("PALUDIS_EBUILD_DIR", LIBEXECDIR "/paludis"))
+ .with_setenv("PALUDIS_REDUCED_GID", stringify(_env->reduced_gid()))
+ .with_setenv("PALUDIS_REDUCED_UID", stringify(_env->reduced_uid()))
+ .with_setenv("PALUDIS_COMMAND", _env->paludis_command());
+
+ int exit_status(0);
+ std::string output("");
+ {
+ std::stringstream s;
+ exit_status = run_command(cmd.with_captured_stdout_stream(&s));
+ output = strip_trailing(std::string((std::istreambuf_iterator<char>(s)), std::istreambuf_iterator<char>()),
+ " \t\n");
+ }
+
+ if (0 == exit_status)
+ {
+ tr1::shared_ptr<Sequence<std::string> > result(new Sequence<std::string>);
+ tokenise_whitespace(output, result->back_inserter());
+ Log::get_instance()->message(ll_debug, lc_no_context) << "Hook '" << file_name()
+ << "' returned success '" << exit_status << "' for auto hook names, result ("
+ << join(result->begin(), result->end(), ", ") << ")";
+ return result;
+ }
+ else
+ {
+ Log::get_instance()->message(ll_warning, lc_no_context, "Hook '" + stringify(file_name())
+ + "' returned failure '" + stringify(exit_status) + "' for auto hook names");
+ return make_shared_ptr(new Sequence<std::string>);
+ }
+}
+
void
FancyHookFile::add_dependencies(const Hook & hook, DirectedGraph<std::string, int> & g)
{
@@ -312,15 +375,19 @@ SoHookFile::SoHookFile(const FSEntry & f, const bool, const Environment * const
if (_dl)
{
_run = reinterpret_cast<HookResult (*)(
- Environment const *, const Hook &)>(
+ const Environment *, 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> &)>(
+ const Environment *, const Hook &, DirectedGraph<std::string, int> &)>(
reinterpret_cast<uintptr_t>(dlsym(_dl, "paludis_hook_add_dependencies")));
+
+ _auto_hook_names = reinterpret_cast<const tr1::shared_ptr<const Sequence<std::string> > (*)(
+ const Environment *)>(
+ reinterpret_cast<uintptr_t>(dlsym(_dl, "paludis_hook_auto_phases")));
}
else
Log::get_instance()->message(ll_warning, lc_no_context, "Opening .so hook '" + stringify(f) + "' failed: " + dlerror());
@@ -347,6 +414,17 @@ SoHookFile::add_dependencies(const Hook & hook, DirectedGraph<std::string, int>
_add_dependencies(_env, hook, g);
}
+const tr1::shared_ptr<const Sequence<std::string > >
+SoHookFile::auto_hook_names() const
+{
+ Context c("When querying auto hook names for .so hook '" + stringify(file_name()) + "':");
+
+ if (! _auto_hook_names)
+ return make_shared_ptr(new Sequence<std::string>);
+
+ return _auto_hook_names(_env);
+}
+
namespace paludis
{
template<>
@@ -354,17 +432,69 @@ namespace paludis
{
const Environment * const env;
std::list<std::pair<FSEntry, bool> > dirs;
+
mutable Mutex hook_files_mutex;
- mutable std::map<std::string, std::list<tr1::shared_ptr<HookFile> > > hook_files;
+ mutable std::map<std::string, tr1::shared_ptr<Sequence<tr1::shared_ptr<HookFile> > > > hook_files;
+ mutable std::map<std::string, std::map<std::string, tr1::shared_ptr<HookFile> > > auto_hook_files;
+ mutable bool has_auto_hook_files;
Implementation(const Environment * const e) :
- env(e)
+ env(e),
+ has_auto_hook_files(false)
+ {
+ }
+
+ void need_auto_hook_files() const
{
+ Lock l(hook_files_mutex);
+
+ if (has_auto_hook_files)
+ return;
+ has_auto_hook_files = true;
+
+ Context context("When loading auto hooks:");
+
+ for (std::list<std::pair<FSEntry, bool> >::const_iterator d(dirs.begin()), d_end(dirs.end()) ;
+ d != d_end ; ++d)
+ {
+ FSEntry d_a(d->first / "auto");
+ if (! d_a.is_directory())
+ continue;
+
+ for (DirIterator e(d_a), e_end ; e != e_end ; ++e)
+ {
+ tr1::shared_ptr<HookFile> hook_file;
+ std::string name;
+
+ if (is_file_with_extension(*e, ".hook", IsFileWithOptions()))
+ {
+ hook_file.reset(new FancyHookFile(*e, d->second, env));
+ name = strip_trailing_string(e->basename(), ".hook");
+ }
+ else if (is_file_with_extension(*e, so_suffix, IsFileWithOptions()))
+ {
+ hook_file.reset(new SoHookFile(*e, d->second, env));
+ name = strip_trailing_string(e->basename(), so_suffix);
+ }
+
+ if (! hook_file)
+ continue;
+
+ const tr1::shared_ptr<const Sequence<std::string> > names(hook_file->auto_hook_names());
+ for (Sequence<std::string>::ConstIterator n(names->begin()), n_end(names->end()) ;
+ n != n_end ; ++n)
+ {
+ if (! auto_hook_files[*n].insert(std::make_pair(name, hook_file)).second)
+ Log::get_instance()->message(ll_warning, lc_context) << "Discarding hook file '" << *e
+ << "' in phase '" << *n << "' because of naming conflict with '"
+ << auto_hook_files[*n].find(name)->second->file_name() << "'";
+ }
+ }
+ }
}
};
}
-
Hooker::Hooker(const Environment * const e) :
PrivateImplementationPattern<Hooker>(new Implementation<Hooker>(e))
{
@@ -379,6 +509,7 @@ Hooker::add_dir(const FSEntry & dir, const bool v)
{
Lock l(_imp->hook_files_mutex);
_imp->hook_files.clear();
+ _imp->auto_hook_files.clear();
_imp->dirs.push_back(std::make_pair(dir, v));
}
@@ -407,6 +538,153 @@ namespace
} pyhookfilehandle;
}
+tr1::shared_ptr<Sequence<tr1::shared_ptr<HookFile> > >
+Hooker::_find_hooks(const Hook & hook) const
+{
+ std::map<std::string, tr1::shared_ptr<HookFile> > hook_files;
+
+ {
+ _imp->need_auto_hook_files();
+ std::map<std::string, std::map<std::string, tr1::shared_ptr<HookFile> > >::const_iterator h(
+ _imp->auto_hook_files.find(hook.name()));
+ if (_imp->auto_hook_files.end() != h)
+ hook_files = h->second;
+ }
+
+ /* named subdirectories */
+ for (std::list<std::pair<FSEntry, bool> >::const_iterator d(_imp->dirs.begin()), d_end(_imp->dirs.end()) ;
+ d != d_end ; ++d)
+ {
+ if (! (d->first / hook.name()).is_directory())
+ continue;
+
+ for (DirIterator e(d->first / hook.name()), e_end ; e != e_end ; ++e)
+ {
+ if (is_file_with_extension(*e, ".bash", IsFileWithOptions()))
+ if (! hook_files.insert(std::make_pair(strip_trailing_string(e->basename(), ".bash"),
+ tr1::shared_ptr<HookFile>(new BashHookFile(*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(), ".bash")))->second->file_name()) + "'");
+
+ if (is_file_with_extension(*e, ".hook", IsFileWithOptions()))
+ if (! hook_files.insert(std::make_pair(strip_trailing_string(e->basename(), ".hook"),
+ tr1::shared_ptr<HookFile>(new FancyHookFile(*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(), ".hook")))->second->file_name()) + "'");
+
+ if (is_file_with_extension(*e, so_suffix, IsFileWithOptions()))
+ if (! hook_files.insert(std::make_pair(strip_trailing_string(e->basename(), so_suffix),
+ 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()) + "'");
+
+#ifdef ENABLE_PYTHON_HOOKS
+ if (is_file_with_extension(*e, ".py", IsFileWithOptions()))
+ {
+ static bool load_try(false);
+ static bool load_ok(false);
+
+ {
+ Lock lock(pyhookfilehandle.mutex);
+
+ if (! load_try)
+ {
+ load_try = true;
+
+ pyhookfilehandle.handle = dlopen("libpaludispythonhooks.so", RTLD_NOW | RTLD_GLOBAL);
+ if (pyhookfilehandle.handle)
+ {
+ pyhookfilehandle.create_py_hook_file_handle =
+ reinterpret_cast<tr1::shared_ptr<HookFile> (*)(
+ const FSEntry &, const bool, const Environment * const)>(
+ reinterpret_cast<uintptr_t>(dlsym(
+ pyhookfilehandle.handle, "create_py_hook_file")));
+ if (pyhookfilehandle.create_py_hook_file_handle)
+ {
+ load_ok = true;
+ }
+ else
+ {
+ Log::get_instance()->message(ll_warning, lc_context,
+ "dlsym(libpaludispythonhooks.so, create_py_hook_file) "
+ "failed due to error '" + stringify(dlerror()) + "'");
+ }
+ }
+ else
+ {
+ Log::get_instance()->message(ll_warning, lc_context,
+ "dlopen(libpaludispythonhooks.so) "
+ "failed due to error '" + stringify(dlerror()) + "'");
+ }
+ }
+ }
+ if (load_ok)
+ {
+ if (! hook_files.insert(std::make_pair(strip_trailing_string(e->basename(), ".py"),
+ tr1::shared_ptr<HookFile>(pyhookfilehandle.create_py_hook_file_handle(
+ *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(), ".py")))->second->file_name()) + "'");
+ }
+ }
+#elif ENABLE_PYTHON
+ if (is_file_with_extension(*e, ".py", IsFileWithOptions()))
+ {
+ Log::get_instance()->message(ll_warning, lc_context) << "Ignoring hook '" << *e << "' because"
+ << " Paludis was built using a dev-libs/boost version older than 1.34.0.";
+ }
+#else
+ if (is_file_with_extension(*e, ".py", IsFileWithOptions()))
+ {
+ Log::get_instance()->message(ll_warning, lc_context) << "Ignoring hook '" << *e << "' because"
+ << " Paludis was built without Python support (also needs >=dev-libs/boost-1.34.0).";
+ }
+#endif
+ }
+ }
+
+ DirectedGraph<std::string, int> hook_deps;
+ {
+ Context context_local("When determining hook dependencies for '" + hook.name() + "':");
+ for (std::map<std::string, tr1::shared_ptr<HookFile> >::const_iterator f(hook_files.begin()), f_end(hook_files.end()) ;
+ f != f_end ; ++f)
+ hook_deps.add_node(f->first);
+
+ for (std::map<std::string, tr1::shared_ptr<HookFile> >::const_iterator f(hook_files.begin()), f_end(hook_files.end()) ;
+ f != f_end ; ++f)
+ f->second->add_dependencies(hook, hook_deps);
+ }
+
+ std::list<std::string> ordered;
+ {
+ Context context_local("When determining hook ordering for '" + hook.name() + "':");
+ try
+ {
+ hook_deps.topological_sort(std::back_inserter(ordered));
+ }
+ catch (const NoGraphTopologicalOrderExistsError & e)
+ {
+ Log::get_instance()->message(ll_warning, lc_context, "Could not resolve dependency order for hook '"
+ + hook.name() + "' due to exception '" + e.message() + "' (" + e.what() + "'), skipping hooks '" +
+ join(e.remaining_nodes()->begin(), e.remaining_nodes()->end(), "', '") + "' and using hooks '" + join(ordered.begin(),
+ ordered.end(), "', '") + "' in that order");;
+ }
+ }
+
+ tr1::shared_ptr<Sequence<tr1::shared_ptr<HookFile> > > result(new Sequence<tr1::shared_ptr<HookFile> >);
+ for (std::list<std::string>::const_iterator o(ordered.begin()), o_end(ordered.end()) ;
+ o != o_end ; ++o)
+ result->push_back(hook_files.find(*o)->second);
+
+ return result;
+}
+
HookResult
Hooker::perform_hook(const Hook & hook) const
{
@@ -461,160 +739,26 @@ Hooker::perform_hook(const Hook & hook) const
/* file hooks, but only if necessary */
Lock l(_imp->hook_files_mutex);
- std::map<std::string, std::list<tr1::shared_ptr<HookFile> > >::iterator h(_imp->hook_files.find(hook.name()));
+ std::map<std::string, tr1::shared_ptr<Sequence<tr1::shared_ptr<HookFile> > > >::iterator h(_imp->hook_files.find(hook.name()));
if (h == _imp->hook_files.end())
- {
- h = _imp->hook_files.insert(std::make_pair(hook.name(), std::list<tr1::shared_ptr<HookFile> >())).first;
-
- std::map<std::string, tr1::shared_ptr<HookFile> > hook_files;
-
- for (std::list<std::pair<FSEntry, bool> >::const_iterator d(_imp->dirs.begin()), d_end(_imp->dirs.end()) ;
- d != d_end ; ++d)
- {
- if (! (d->first / hook.name()).is_directory())
- continue;
-
- for (DirIterator e(d->first / hook.name()), e_end ; e != e_end ; ++e)
- {
- if (is_file_with_extension(*e, ".bash", IsFileWithOptions()))
- if (! hook_files.insert(std::make_pair(strip_trailing_string(e->basename(), ".bash"),
- tr1::shared_ptr<HookFile>(new BashHookFile(*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(), ".bash")))->second->file_name()) + "'");
-
- if (is_file_with_extension(*e, ".hook", IsFileWithOptions()))
- if (! hook_files.insert(std::make_pair(strip_trailing_string(e->basename(), ".hook"),
- tr1::shared_ptr<HookFile>(new FancyHookFile(*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(), ".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),
- 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()) + "'");
-
-#ifdef ENABLE_PYTHON_HOOKS
- if (is_file_with_extension(*e, ".py", IsFileWithOptions()))
- {
- static bool load_try(false);
- static bool load_ok(false);
-
- {
- Lock lock(pyhookfilehandle.mutex);
-
- if (! load_try)
- {
- load_try = true;
-
- pyhookfilehandle.handle = dlopen("libpaludispythonhooks.so", RTLD_NOW | RTLD_GLOBAL);
- if (pyhookfilehandle.handle)
- {
- pyhookfilehandle.create_py_hook_file_handle =
- reinterpret_cast<tr1::shared_ptr<HookFile> (*)(
- const FSEntry &, const bool, const Environment * const)>(
- reinterpret_cast<uintptr_t>(dlsym(
- pyhookfilehandle.handle, "create_py_hook_file")));
- if (pyhookfilehandle.create_py_hook_file_handle)
- {
- load_ok = true;
- }
- else
- {
- Log::get_instance()->message(ll_warning, lc_context,
- "dlsym(libpaludispythonhooks.so, create_py_hook_file) "
- "failed due to error '" + stringify(dlerror()) + "'");
- }
- }
- else
- {
- Log::get_instance()->message(ll_warning, lc_context,
- "dlopen(libpaludispythonhooks.so) "
- "failed due to error '" + stringify(dlerror()) + "'");
- }
- }
- }
- if (load_ok)
- {
- if (! hook_files.insert(std::make_pair(strip_trailing_string(e->basename(), ".py"),
- tr1::shared_ptr<HookFile>(pyhookfilehandle.create_py_hook_file_handle(
- *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(), ".py")))->second->file_name()) + "'");
- }
- }
-#elif ENABLE_PYTHON
- if (is_file_with_extension(*e, ".py", IsFileWithOptions()))
- {
- Log::get_instance()->message(ll_warning, lc_context) << "Ignoring hook '" << *e << "' because"
- << " Paludis was built using a dev-libs/boost version older than 1.34.0.";
- }
-#else
- if (is_file_with_extension(*e, ".py", IsFileWithOptions()))
- {
- Log::get_instance()->message(ll_warning, lc_context) << "Ignoring hook '" << *e << "' because"
- << " Paludis was built without Python support (also needs >=dev-libs/boost-1.34.0).";
- }
-#endif
- }
- }
-
- DirectedGraph<std::string, int> hook_deps;
- {
- Context context_local("When determining hook dependencies for '" + hook.name() + "':");
- for (std::map<std::string, tr1::shared_ptr<HookFile> >::const_iterator f(hook_files.begin()), f_end(hook_files.end()) ;
- f != f_end ; ++f)
- hook_deps.add_node(f->first);
-
- for (std::map<std::string, tr1::shared_ptr<HookFile> >::const_iterator f(hook_files.begin()), f_end(hook_files.end()) ;
- f != f_end ; ++f)
- f->second->add_dependencies(hook, hook_deps);
- }
-
- std::list<std::string> ordered;
- {
- Context context_local("When determining hook ordering for '" + hook.name() + "':");
- try
- {
- hook_deps.topological_sort(std::back_inserter(ordered));
- }
- catch (const NoGraphTopologicalOrderExistsError & e)
- {
- Log::get_instance()->message(ll_warning, lc_context, "Could not resolve dependency order for hook '"
- + hook.name() + "' due to exception '" + e.message() + "' (" + e.what() + "'), skipping hooks '" +
- join(e.remaining_nodes()->begin(), e.remaining_nodes()->end(), "', '") + "' and using hooks '" + join(ordered.begin(),
- ordered.end(), "', '") + "' in that order");;
- }
- }
-
- for (std::list<std::string>::const_iterator o(ordered.begin()), o_end(ordered.end()) ;
- o != o_end ; ++o)
- h->second.push_back(hook_files.find(*o)->second);
- }
+ h = _imp->hook_files.insert(std::make_pair(hook.name(), _find_hooks(hook))).first;
- if (! h->second.empty())
+ if (! h->second->empty())
{
do
{
switch (hook.output_dest)
{
case hod_stdout:
- for (std::list<tr1::shared_ptr<HookFile> >::const_iterator f(h->second.begin()),
- f_end(h->second.end()) ; f != f_end ; ++f)
+ for (Sequence<tr1::shared_ptr<HookFile> >::ConstIterator f(h->second->begin()),
+ f_end(h->second->end()) ; f != f_end ; ++f)
result.max_exit_status = std::max(result.max_exit_status, (*f)->run(hook).max_exit_status);
continue;
case hod_grab:
- for (std::list<tr1::shared_ptr<HookFile> >::const_iterator f(h->second.begin()),
- f_end(h->second.end()) ; f != f_end ; ++f)
+ for (Sequence<tr1::shared_ptr<HookFile> >::ConstIterator f(h->second->begin()),
+ f_end(h->second->end()) ; f != f_end ; ++f)
{
HookResult tmp((*f)->run(hook));
if (tmp > result)
diff --git a/paludis/hooker.hh b/paludis/hooker.hh
index f463dde..06e9111 100644
--- a/paludis/hooker.hh
+++ b/paludis/hooker.hh
@@ -1,7 +1,7 @@
/* vim: set sw=4 sts=4 et foldmethod=syntax : */
/*
- * Copyright (c) 2007 Ciaran McCreesh
+ * Copyright (c) 2007, 2008 Ciaran McCreesh
*
* 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
@@ -23,6 +23,8 @@
#include <paludis/util/instantiation_policy.hh>
#include <paludis/util/private_implementation_pattern.hh>
#include <paludis/util/graph-fwd.hh>
+#include <paludis/util/sequence-fwd.hh>
+#include <paludis/util/tr1_memory.hh>
#include <string>
/** \file
@@ -62,6 +64,7 @@ namespace paludis
virtual HookResult run(const Hook &) const PALUDIS_ATTRIBUTE((warn_unused_result)) = 0;
virtual const FSEntry file_name() const = 0;
virtual void add_dependencies(const Hook &, DirectedGraph<std::string, int> &) = 0;
+ virtual const tr1::shared_ptr<const Sequence<std::string> > auto_hook_names() const = 0;
};
/**
@@ -74,6 +77,9 @@ namespace paludis
private PrivateImplementationPattern<Hooker>,
private InstantiationPolicy<Hooker, instantiation_method::NonCopyableTag>
{
+ private:
+ tr1::shared_ptr<Sequence<tr1::shared_ptr<HookFile> > > _find_hooks(const Hook &) const;
+
public:
///\name Basic operations
///\{
diff --git a/paludis/install_task.cc b/paludis/install_task.cc
index 881c914..115b99b 100644
--- a/paludis/install_task.cc
+++ b/paludis/install_task.cc
@@ -1035,9 +1035,20 @@ InstallTask::_execute()
void
InstallTask::execute()
{
+ bool success(false);
try
{
+ if (0 != perform_hook(Hook("install_task_execute_pre")
+ ("TARGETS", join(
+ _imp->raw_targets.begin(), _imp->raw_targets.end(), " "))
+ ("PRETEND", stringify(_imp->pretend))
+ ("FETCH_ONLY", stringify(_imp->fetch_only))
+ ("DEPLIST_HAS_ERRORS", stringify(_imp->dep_list.has_errors()))
+ ).max_exit_status)
+ throw InstallActionError("Install task execute aborted by hook");
+
_execute();
+ success = true;
}
catch (const AmbiguousPackageNameError & e)
{
@@ -1074,6 +1085,16 @@ InstallTask::execute()
_imp->had_resolution_failures = true;
on_multiple_set_targets_specified(e);
}
+
+ if (0 != perform_hook(Hook("install_task_execute_post")
+ ("TARGETS", join(
+ _imp->raw_targets.begin(), _imp->raw_targets.end(), " "))
+ ("PRETEND", stringify(_imp->pretend))
+ ("FETCH_ONLY", stringify(_imp->fetch_only))
+ ("SUCCESS", stringify(success))
+ ("DEPLIST_HAS_ERRORS", stringify(_imp->dep_list.has_errors()))
+ ).max_exit_status)
+ throw InstallActionError("Install task execute aborted by hook");
}
const DepList &
diff --git a/paludis/python_hooks.cc b/paludis/python_hooks.cc
index 93d3afd..e915fda 100644
--- a/paludis/python_hooks.cc
+++ b/paludis/python_hooks.cc
@@ -12,6 +12,8 @@
#include <paludis/util/strip.hh>
#include <paludis/util/system.hh>
#include <paludis/util/mutex.hh>
+#include <paludis/util/sequence.hh>
+#include <paludis/util/make_shared_ptr.hh>
#include <set>
@@ -69,7 +71,13 @@ namespace
}
virtual void add_dependencies(const Hook &, DirectedGraph<std::string, int> &);
+
+ virtual const tr1::shared_ptr<const Sequence<std::string> > auto_hook_names() const
+ {
+ return make_shared_ptr(new Sequence<std::string>);
+ }
};
+
Mutex PyHookFile::_mutex;
bp::dict PyHookFile::_output_wrapper_namespace;
bp::dict PyHookFile::_local_namespace_base;