]> git.vanrenterghem.biz Git - git.ikiwiki.info.git/commitdiff
Merge commit 'origin/master' into prv/po
authorintrigeri <intrigeri@boum.org>
Sun, 2 Nov 2008 12:11:00 +0000 (13:11 +0100)
committerintrigeri <intrigeri@boum.org>
Sun, 2 Nov 2008 12:11:00 +0000 (13:11 +0100)
1  2 
IkiWiki.pm
doc/plugins/write.mdwn

diff --combined IkiWiki.pm
index 67cd2147d2eb65b7d74356208b63205de231f9bb,bab7b707aa6c485338fb3b863760e8019cd65e1c..90fedca4f5dfb5614c229be58f453ea83307ea28
@@@ -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,
                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/^\/+//) {
                $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 '<span class="date">'.formattime(@_).'</span>';
  } #}}}
  
  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 857d176d5e172d6b263335f833a997e70024560f,abcabbdc39e43871af4b491b47b1540fda99a34f..f147b0766c385ce5d2b8b9890f6b2ea0aa58a5a8
@@@ -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 "<time>".formattime(@_)."</time>";
+       });
+ 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.