From: intrigeri Date: Sun, 2 Nov 2008 12:11:00 +0000 (+0100) Subject: Merge commit 'origin/master' into prv/po X-Git-Tag: 3.15~408^2~13 X-Git-Url: http://git.vanrenterghem.biz/git.ikiwiki.info.git/commitdiff_plain/77136538788350ad2decaa445704ba5738074736?ds=inline;hp=-c Merge commit 'origin/master' into prv/po --- 77136538788350ad2decaa445704ba5738074736 diff --combined IkiWiki.pm index 67cd2147d,bab7b707a..90fedca4f --- a/IkiWiki.pm +++ b/IkiWiki.pm @@@ -21,6 -21,7 +21,7 @@@ our @EXPORT = qw(hook debug error templ bestlink htmllink readfile writefile pagetype srcfile pagename displaytime will_render gettext urlto targetpage add_underlay pagetitle titlepage linkpage newpagefile + inject %config %links %pagestate %wikistate %renderedfiles %pagesources %destsources); our $VERSION = 2.00; # plugin interface version, next is ikiwiki version @@@ -381,6 -382,13 +382,13 @@@ sub getsetup () { #{{ safe => 0, rebuild => 0, }, + test_receive => { + type => "internal", + default => 0, + description => "running in receive test mode", + safe => 0, + rebuild => 0, + }, getctime => { type => "internal", default => 0, @@@ -403,7 -411,7 +411,7 @@@ rebuild => 0, }, allow_symlinks_before_srcdir => { - type => "string", + type => "boolean", default => 0, description => "allow symlinks in the path leading to the srcdir (potentially insecure)", safe => 0, @@@ -647,19 -655,8 +655,19 @@@ sub newpagefile ($$) { #{{ sub targetpage ($$) { #{{{ my $page=shift; my $ext=shift; - - if (! $config{usedirs} || $page eq 'index') { + + my $targetpage=''; + run_hooks(targetpage => sub { + $targetpage=shift->( + page => $page, + ext => $ext, + ); + }); + + if (defined $targetpage && (length($targetpage) > 0)) { + return $targetpage; + } + elsif (! $config{usedirs} || $page eq 'index') { return $page.".".$ext; } else { @@@ -807,7 -804,6 +815,7 @@@ sub will_render ($$;$) { #{{ sub bestlink ($$) { #{{{ my $page=shift; my $link=shift; + my $res=undef; my $cwd=$page; if ($link=~s/^\/+//) { @@@ -822,35 -818,25 +830,35 @@@ $l.=$link; if (exists $links{$l}) { - return $l; + $res=$l; } elsif (exists $pagecase{lc $l}) { - return $pagecase{lc $l}; + $res=$pagecase{lc $l}; } - } while $cwd=~s{/?[^/]+$}{}; + } while ($cwd=~s{/?[^/]+$}{} && ! defined $res); - if (length $config{userdir}) { + if (! defined $res && length $config{userdir}) { my $l = "$config{userdir}/".lc($link); if (exists $links{$l}) { - return $l; + $res=$l; } elsif (exists $pagecase{lc $l}) { - return $pagecase{lc $l}; + $res=$pagecase{lc $l}; } } - #print STDERR "warning: page $page, broken link: $link\n"; - return ""; + if (defined $res) { + run_hooks(tweakbestlink => sub { + $res=shift->( + page => $page, + link => $res); + }); + return $res; + } + else { + #print STDERR "warning: page $page, broken link: $link\n"; + return ""; + } } #}}} sub isinlinableimage ($) { #{{{ @@@ -920,23 -906,13 +928,13 @@@ sub abs2rel ($$) { #{{ } #}}} sub displaytime ($;$) { #{{{ - my $time=shift; - my $format=shift; - if (exists $hooks{displaytime}) { - my $ret; - run_hooks(displaytime => sub { - $ret=shift->($time, $format) - }); - return $ret; - } - else { - return formattime($time, $format); - } + # Plugins can override this function to mark up the time to + # display. + return ''.formattime(@_).''; } #}}} sub formattime ($;$) { #{{{ - # Plugins can override this function to mark up the time for - # display. + # Plugins can override this function to format the time. my $time=shift; my $format=shift; if (! defined $format) { @@@ -955,10 -931,6 +953,10 @@@ sub beautify_urlpath ($) { #{{ $url =~ s!/index.$config{htmlext}$!/!; } + run_hooks(tweakurlpath => sub { + $url=shift->(url => $url); + }); + # Ensure url is not an empty link, and # if it's relative, make that explicit to avoid colon confusion. if ($url !~ /^\//) { @@@ -1610,6 -1582,10 +1608,10 @@@ sub rcs_getctime ($) { #{{ $hooks{rcs}{rcs_getctime}{call}->(@_); } #}}} + sub rcs_receive () { #{{{ + $hooks{rcs}{rcs_receive}{call}->(); + } #}}} + sub globlist_to_pagespec ($) { #{{{ my @globlist=split(' ', shift); @@@ -1702,6 -1678,31 +1704,31 @@@ sub yesno ($) { #{{ return (defined $val && lc($val) eq gettext("yes")); } #}}} + sub inject { #{{{ + # Injects a new function into the symbol table to replace an + # exported function. + my %params=@_; + + # This is deep ugly perl foo, beware. + no strict; + no warnings; + if (! defined $params{parent}) { + $params{parent}='::'; + $params{old}=\&{$params{name}}; + $params{name}=~s/.*:://; + } + my $parent=$params{parent}; + foreach my $ns (grep /^\w+::/, keys %{$parent}) { + $ns = $params{parent} . $ns; + inject(%params, parent => $ns) unless $ns eq '::main::'; + *{$ns . $params{name}} = $params{call} + if exists ${$ns}{$params{name}} && + \&{${$ns}{$params{name}}} == $params{old}; + } + use strict; + use warnings; + } #}}} + sub pagespec_merge ($$) { #{{{ my $a=shift; my $b=shift; @@@ -1796,7 -1797,7 +1823,7 @@@ sub pagespec_valid ($) { #{{ my $sub=pagespec_translate($spec); return ! $@; } #}}} - + sub glob2re ($) { #{{{ my $re=quotemeta(shift); $re=~s/\\\*/.*/g; diff --combined doc/plugins/write.mdwn index 857d176d5,abcabbdc3..f147b0766 --- a/doc/plugins/write.mdwn +++ b/doc/plugins/write.mdwn @@@ -360,13 -360,6 +360,6 @@@ This hook is called whenever ikiwiki no the state is saved. The function can save other state, modify values before they're saved, etc. - ### displaytime - - hook(type => "displaytime", id => "foo", call => \&display); - - This hook can be registered to override the regular `displaytime` function. - Only the last displaytime hook will be used. - ### renamepage hook(type => "renamepage", id => "foo", call => \&renamepage); @@@ -434,36 -427,6 +427,36 @@@ describes the plugin as a whole. For ex and undef if a rebuild could be needed in some circumstances, but is not strictly required. +### targetpage + + hook(type => "targetpage", id => "foo", call => \&targetpage); + +This hook can be used to override the name of the file a page should +be compiled into. + +It should return the target filename. + +### tweakurlpath + + hook(type => "tweakurlpath", id => "foo", call => \&tweakurlpath); + +This hook can be used to modify the internal urls generated by +ikiwiki; it is run just after ikiwiki has removed the trailing +`index.html`, in case `usedirs` is enabled. + +It should return the modified url. + +### tweakbestlink + + hook(type => "tweakbestlink", id => "foo", call => \&tweakbestlink); + +This hook can be used to modify the page returned by `bestlink`. It is +passed named parameters `page` and `link`. These are, respectively, +the page where the link will appear and the link ikiwiki would choose +as the best one, if no `tweakbestlink` hook was in effect. + +It should return the modified link. + ## Plugin interface To import the ikiwiki plugin interface: @@@ -857,6 -820,30 +850,30 @@@ it up in the history It's ok if this is not implemented, and throws an error. + #### `rcs_receive()` + + This is called when ikiwiki is running as a pre-receive hook (or + equivalent), and is testing if changes pushed into the RCS from an + untrusted user should be accepted. This is optional, and doesn't make + sense to implement for all RCSs. + + It should examine the incoming changes, and do any sanity + checks that are appropriate for the RCS to limit changes to safe file adds, + removes, and changes. If something bad is found, it should exit + nonzero, to abort the push. Otherwise, it should return a list of + files that were changed, in the form: + + { + file => # name of file that was changed + action => # either "add", "change", or "remove" + path => # temp file containing the new file content, only + # needed for "add"/"change", and only if the file + # is an attachment, not a page + } + + The list will then be checked to make sure that each change is one that + is allowed to be made via the web interface. + ### PageSpec plugins It's also possible to write plugins that add new functions to @@@ -884,6 -871,56 +901,56 @@@ By the way, to parse a ikiwiki setup fi program just needs to do something like: `use IkiWiki::Setup; IkiWiki::Setup::load($filename)` + ### Function overriding + + Sometimes using ikiwiki's pre-defined hooks is not enough. Your plugin + may need to replace one of ikiwiki's own functions with a modified version, + or wrap one of the functions. + + For example, your plugin might want to override `displaytime`, to change + the html markup used when displaying a date. Or it might want to override + `IkiWiki::formattime`, to change how a date is formatted. Or perhaps you + want to override `bestlink` and change how ikiwiki deals with WikiLinks. + + By venturing into this territory, your plugin is becoming tightly tied to + ikiwiki's internals. And it might break if those internals change. But + don't let that stop you, if you're brave. + + Ikiwiki provides an `inject()` function, that is a powerful way to replace + any function with one of your own. This even allows you to inject a + replacement for an exported function, like `bestlink`. Everything that + imports that function will get your version instead. Pass it the name of + the function to replace, and a new function to call. + + For example, here's how to replace `displaytime` with a version using HTML 5 + markup: + + inject(name => 'IkiWiki::displaytime', call => sub { + return ""; + }); + + Here's how to wrap `bestlink` with a version that tries to handle + plural words: + + my $origbestlink=\&bestlink; + inject(name => 'IkiWiki::bestlink', call => \&mybestlink); + + sub deplural ($) { + my $word=shift; + $word =~ s/e?s$//; # just an example :-) + return $word; + } + + sub mybestlink ($$) { + my $page=shift; + my $link=shift; + my $ret=$origbestlink->($page, $link); + if (! length $ret) { + $ret=$origbestlink->($page, deplural($link)); + } + return $ret; + } + ### Javascript Some plugins use javascript to make ikiwiki look a bit more web-2.0-ish.