X-Git-Url: http://git.vanrenterghem.biz/git.ikiwiki.info.git/blobdiff_plain/61426a71868a6863115b0a4e0467756e97953092..a020228805485f19e35f72d0be50d1013d5109ec:/IkiWiki.pm?ds=sidebyside diff --git a/IkiWiki.pm b/IkiWiki.pm index 9a81c7da4..bab7b707a 100644 --- a/IkiWiki.pm +++ b/IkiWiki.pm @@ -12,16 +12,17 @@ use Storable; use open qw{:utf8 :std}; use vars qw{%config %links %oldlinks %pagemtime %pagectime %pagecase - %pagestate %renderedfiles %oldrenderedfiles %pagesources - %destsources %depends %hooks %forcerebuild $gettext_obj - %loaded_plugins}; + %pagestate %wikistate %renderedfiles %oldrenderedfiles + %pagesources %destsources %depends %hooks %forcerebuild + $gettext_obj %loaded_plugins}; use Exporter q{import}; our @EXPORT = qw(hook debug error template htmlpage add_depends pagespec_match bestlink htmllink readfile writefile pagetype srcfile pagename displaytime will_render gettext urlto targetpage - add_underlay pagetitle titlepage linkpage - %config %links %pagestate %renderedfiles + 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 our $version='unknown'; # VERSION_AUTOREPLACE done by Makefile, DNE @@ -198,6 +199,13 @@ sub getsetup () { #{{{ safe => 0, # changing requires manual transition rebuild => 1, }, + indexpages => { + type => "boolean", + default => 0, + description => "use page/index.mdwn source files", + safe => 1, + rebuild => 1, + }, discussion => { type => "boolean", default => 1, @@ -374,6 +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, @@ -396,7 +411,7 @@ sub getsetup () { #{{{ 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, @@ -619,16 +634,32 @@ sub pagename ($) { #{{{ my $type=pagetype($file); my $page=$file; $page=~s/\Q.$type\E*$// if defined $type && !$hooks{htmlize}{$type}{keepextension}; + if ($config{indexpages} && $page=~/(.*)\/index$/) { + $page=$1; + } return $page; } #}}} +sub newpagefile ($$) { #{{{ + my $page=shift; + my $type=shift; + + if (! $config{indexpages} || $page eq 'index') { + return $page.".".$type; + } + else { + return $page."/index.".$type; + } +} #}}} + sub targetpage ($$) { #{{{ my $page=shift; my $ext=shift; - if (! $config{usedirs} || $page =~ /^index$/ ) { + if (! $config{usedirs} || $page eq 'index') { return $page.".".$ext; - } else { + } + else { return $page."/index.".$ext; } } #}}} @@ -658,11 +689,12 @@ sub srcfile ($;$) { #{{{ sub add_underlay ($) { #{{{ my $dir=shift; - if ($dir=~/^\//) { - unshift @{$config{underlaydirs}}, $dir; + if ($dir !~ /^\//) { + $dir="$config{underlaydir}/../$dir"; } - else { - unshift @{$config{underlaydirs}}, "$config{underlaydir}/../$dir"; + + if (! grep { $_ eq $dir } @{$config{underlaydirs}}) { + unshift @{$config{underlaydirs}}, $dir; } return 1; @@ -750,7 +782,7 @@ sub will_render ($$;$) { #{{{ # Important security check. if (-e "$config{destdir}/$dest" && ! $config{rebuild} && - ! grep { $_ eq $dest } (@{$renderedfiles{$page}}, @{$oldrenderedfiles{$page}})) { + ! grep { $_ eq $dest } (@{$renderedfiles{$page}}, @{$oldrenderedfiles{$page}}, @{$wikistate{editpage}{previews}})) { error("$config{destdir}/$dest independently created, not overwriting with version from $page"); } @@ -874,6 +906,13 @@ sub abs2rel ($$) { #{{{ } #}}} sub displaytime ($;$) { #{{{ + # Plugins can override this function to mark up the time to + # display. + return ''.formattime(@_).''; +} #}}} + +sub formattime ($;$) { #{{{ + # Plugins can override this function to format the time. my $time=shift; my $format=shift; if (! defined $format) { @@ -1318,9 +1357,11 @@ sub loadindex () { #{{{ my $pages; if (exists $index->{version} && ! ref $index->{version}) { $pages=$index->{page}; + %wikistate=%{$index->{state}}; } else { $pages=$index; + %wikistate=(); } foreach my $src (keys %$pages) { @@ -1368,6 +1409,7 @@ sub saveindex () { #{{{ my $newfile="$config{wikistatedir}/indexdb.new"; my $cleanup = sub { unlink($newfile) }; open (my $out, '>', $newfile) || error("cannot write to $newfile: $!", $cleanup); + my %index; foreach my $page (keys %pagemtime) { next unless $pagemtime{$page}; @@ -1392,6 +1434,14 @@ sub saveindex () { #{{{ } } } + + $index{state}={}; + foreach my $id (@hookids) { + foreach my $key (keys %{$wikistate{$id}}) { + $index{state}{$id}{$key}=$wikistate{$id}{$key}; + } + } + $index{version}="3"; my $ret=Storable::nstore_fd(\%index, $out); return if ! defined $ret || ! $ret; @@ -1532,6 +1582,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); @@ -1624,6 +1678,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; @@ -1718,7 +1797,7 @@ sub pagespec_valid ($) { #{{{ my $sub=pagespec_translate($spec); return ! $@; } #}}} - + sub glob2re ($) { #{{{ my $re=quotemeta(shift); $re=~s/\\\*/.*/g; @@ -1885,4 +1964,61 @@ sub match_creation_year ($$;@) { #{{{ } } #}}} +sub match_user ($$;@) { #{{{ + shift; + my $user=shift; + my %params=@_; + + if (! exists $params{user}) { + return IkiWiki::FailReason->new("no user specified"); + } + + if (defined $params{user} && lc $params{user} eq lc $user) { + return IkiWiki::SuccessReason->new("user is $user"); + } + elsif (! defined $params{user}) { + return IkiWiki::FailReason->new("not logged in"); + } + else { + return IkiWiki::FailReason->new("user is $params{user}, not $user"); + } +} #}}} + +sub match_admin ($$;@) { #{{{ + shift; + shift; + my %params=@_; + + if (! exists $params{user}) { + return IkiWiki::FailReason->new("no user specified"); + } + + if (defined $params{user} && IkiWiki::is_admin($params{user})) { + return IkiWiki::SuccessReason->new("user is an admin"); + } + elsif (! defined $params{user}) { + return IkiWiki::FailReason->new("not logged in"); + } + else { + return IkiWiki::FailReason->new("user is not an admin"); + } +} #}}} + +sub match_ip ($$;@) { #{{{ + shift; + my $ip=shift; + my %params=@_; + + if (! exists $params{ip}) { + return IkiWiki::FailReason->new("no IP specified"); + } + + if (defined $params{ip} && lc $params{ip} eq lc $ip) { + return IkiWiki::SuccessReason->new("IP is $ip"); + } + else { + return IkiWiki::FailReason->new("IP is $params{ip}, not $ip"); + } +} #}}} + 1