# # # add_file "contrib/ext_hooks.lua.in" # content [9465ba457136d50edccaad82bdab09870e6bff77] # # add_file "contrib/ext_hooks_expand.pl" # content [80d323d81b14a00ba5aeeeafb18a2474a157262b] # # patch "ChangeLog" # from [7d1211b293f94886ad3e3a3c732980ad4cc94807] # to [2d7c5ffe4b75e6408186b26ff7d45aa46889eaae] # # patch "contrib/README" # from [ccc023e05e18cba04e516b2f4b0d594bc55c89c6] # to [03b97be886f1ea1dce0689113b1364406a87c9ad] # ============================================================ --- contrib/ext_hooks.lua.in 9465ba457136d50edccaad82bdab09870e6bff77 +++ contrib/ext_hooks.lua.in 9465ba457136d50edccaad82bdab09870e6bff77 @@ -0,0 +1,75 @@ +-- this is an add-on to the standard set of lua hooks for monotone; +-- the intention is to store the hooks in arrays of hooks and to load +-- extra .lua files from a directory given by the environment variable +-- $MTN_LUAHOOKSDIR +-- +-- Hooks are supposed to be added using the following syntax: +-- +-- add_hook("edit_comment", +-- function (commentary, user_log_message) +-- -- do whatever needs to be done +-- end +-- ) +-- +-- The existing standard hooks are automatically added as the first item +-- to each array of hooks, and will be therefore executed first. +-- +-- Also, should the standard hook functions be defined by any of the loaded +-- .lua files, the last definition will be added as the last item to each +-- array of hooks. +-- +-- It's perfectly possible to have several implementations of the same +-- hook. Those will be executed in the same order the were added as hooks. +-- +-- Any non-nil result is stored in a global variable named like the hook +-- with "res_" prepended. For example, any non-nil result from "edit_comment" +-- hooks is stored in the global variable res_edit_comment. When all +-- "edit_comment" hooks have been executed, the contents of res_edit_comment +-- is returned by the global edit_comment function. The same goes for all +-- other hook executors. +-- +-- ---------------------------------------------------------------------------- + +-- Define the table that will contain pointers to all the hooks. +-- Each entry is the tuple , where {name} is the name +-- of the hook in question and fn-table is a table of functions. +mtn_luahooks = {} + +-- Define functions to manipulate the table of hooks. +function add_hook(name, fun) + if name ~= nil and fun ~= nil then + if mtn_luahooks[name] == nil then mtn_luahooks[name] = {} end + table.insert(mtn_luahooks[name], fun) + end +end + +_known_hooks = { + "@@HOOKS_LIST@@", +} +function _add_known_hooks() + for i,name in pairs(_known_hooks) do + local fntab = getfenv(0) + local fn = fntab[name] + fntab[name] = nil + setfenv(0, fntab) + add_hook(name,fn) + end +end + +-- This stores the definitions of all the known hooks first in the table. +_add_known_hooks() + +-- Load all the *.lua files found in $MTN_LUAHOOKSDIR if that variable is +-- defined. +_mtn_luahooksdir = os.getenv("MTN_LUAHOOKSDIR") +if _mtn_luahooksdir ~= nil and _mtn_luahooksdir ~= "" then + includedirpattern(_mtn_luahooksdir, "*.lua") +end + +-- If anyone was foolish enough to define a hook function directly instead +-- of using "add_hook", the last will win and will be inserted in the table +-- of hooks. +_add_known_hooks() + +-- Finally, redefine all known functions to use the hooks to do their job +@@HOOKS_FUNCTIONS@@ ============================================================ --- contrib/ext_hooks_expand.pl 80d323d81b14a00ba5aeeeafb18a2474a157262b +++ contrib/ext_hooks_expand.pl 80d323d81b14a00ba5aeeeafb18a2474a157262b @@ -0,0 +1,96 @@ +#! /usr/bin/perl + +use warnings; +use strict; +use File::Basename; +use File::Spec; + +my $here = dirname($0); +my $there = File::Spec->catdir($here,File::Spec->updir()); +my $monotone_texi = File::Spec->catfile($there, "monotone.texi"); +my $ext_hooks_lua_in = File::Spec->catfile($here, "ext_hooks.lua.in"); +my $ext_hooks_lua = File::Spec->catfile($here, "ext_hooks.lua"); + +# Format: $name => $arglist +my %hooks = (); + +open INPUT, $monotone_texi || + die "Couldn't open $monotone_texi for reading: $!\n"; + +# First, read until we find the Hooks section +while() { + chomp; + last if (/address@hidden/); +} + +# Now, parse all the hooks docs until we find the Additional Lua Functions +# section +while() { + chomp; + last if (/address@hidden/); + if (/address@hidden(\w+)\s*\((address@hidden(,address@hidden)*)?\)\s*$/) { + my $name = $1; + my $arglist = ""; + if (defined $2) { + $arglist = join(", ", + map { + my $x = $_; + $x =~ s/address@hidden(\w+)\}\s*$/$1/; + $x; + } split(/,\s*/, $2)); + } + $hooks{$name} = $arglist; + } +} + +close INPUT; + +foreach my $n (sort keys %hooks) { + print $n," => \"",$hooks{$n},"\"\n"; +} + +open INPUT, $ext_hooks_lua_in || + die "Couldn't open $ext_hooks_lua_in for reading: $!\n"; +open OUTPUT, ">$ext_hooks_lua" || + die "Couldn't open $ext_hooks_lua for writing: $!\n"; + +# Format : $name => [ list of strings ] +my %expansions = ( HOOKS_LIST => [], + HOOKS_FUNCTIONS => []); + +foreach my $n (sort keys %hooks) { + push(@{$expansions{HOOKS_LIST}}, $n); + push(@{$expansions{HOOKS_FUNCTIONS}}, +"function $n ($hooks{$n}) + local i + local fn + res_$n = nil + for i,fn in pairs(mtn_luahooks[\"$n\"]) do + res = fn($hooks{$n}) + if res ~= nil then res_$n = res end + end + return res_$n +end" + ); +} + +while() { + chomp; + if (/^(.*)address@hidden@(\w+)address@hidden@(.*)$/) { + my $prefix = $1; + my $listname = $2; + my $postfix = $3; + if (defined $expansions{$listname}) { + foreach my $item (@{$expansions{$listname}}) { + print OUTPUT $prefix,$item,$postfix,"\n"; + } + } else { + print OUTPUT $prefix,$listname,$postfix,"\n"; + } + } else { + print OUTPUT $_,"\n"; + } +} + +close OUTPUT; +close INPUT; ============================================================ --- ChangeLog 7d1211b293f94886ad3e3a3c732980ad4cc94807 +++ ChangeLog 2d7c5ffe4b75e6408186b26ff7d45aa46889eaae @@ -1,3 +1,14 @@ +2006-11-16 Richard Levitte + + * contrib/ext_hooks.lua.in, contrib/ext_hooks_expand.pl: New + files that implement a system that allows easy addition of hooks + implementations without having to edit any file. You need to + run the perl script contrib/ext_hooks_expand.pl to produce the + file contrib/ext_hooks.lua, using contrib/ext_hooks.lua.in as + a template and the hook function definitions found in + monotone.texi. + * README: Add a small blurb about the above files. + 2006-11-15 Richard Levitte * lua.cc (LUAEXT): Implement includedirpattern(), which is like ============================================================ --- contrib/README ccc023e05e18cba04e516b2f4b0d594bc55c89c6 +++ contrib/README 03b97be886f1ea1dce0689113b1364406a87c9ad @@ -34,3 +34,10 @@ licenses. -- mtn_cheat_sheet.svg: A SVG image inspired by Mercurial's QuickStart Guides (http://people.type-z.org/seb/mercurial/v1.0/) + + -- ext_hooks.lua.in, ext_hooks_expand.pl: run ext_hooks_expand.pl and you + will get ext_hooks.lua, a hooks system that allows loading several + implementations of the same hooks from a bunch of .lua files stored in + a directory pointed at by $MTN_LUAHOOKSDIR. Hooks are commonly added + using the function add_hook(). There is simple documentation at the + top of ext_hooks.lua.in.