X-Git-Url: https://sipb.mit.edu/gitweb.cgi/ikiwiki.git/blobdiff_plain/16d51e67a7e7257739e1cb3f9a3713d448065e5d..0e31e924e88d660b75bb8d33fb6ca1eb80a8a5e2:/IkiWiki.pm diff --git a/IkiWiki.pm b/IkiWiki.pm index edee8aacb..735dc97b1 100644 --- a/IkiWiki.pm +++ b/IkiWiki.pm @@ -21,6 +21,7 @@ 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 newpagefile + inject %config %links %pagestate %wikistate %renderedfiles %pagesources %destsources); our $VERSION = 2.00; # plugin interface version, next is ikiwiki version @@ -119,7 +120,7 @@ sub getsetup () { #{{{ }, default_plugins => { type => "internal", - default => [qw{mdwn link inline htmlscrubber passwordauth + default => [qw{mdwn link inline meta htmlscrubber passwordauth openid signinedit lockedit conditional recentchanges parentlinks editpage}], description => "plugins to enable by default", @@ -381,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, @@ -395,6 +403,13 @@ sub getsetup () { #{{{ safe => 0, rebuild => 0, }, + wikistatedir => { + type => "internal", + default => undef, + description => "path to the .ikiwiki directory holding ikiwiki state", + safe => 0, + rebuild => 0, + }, setupfile => { type => "internal", default => undef, @@ -403,7 +418,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, @@ -459,7 +474,7 @@ sub checkconfig () { #{{{ } $config{wikistatedir}="$config{srcdir}/.ikiwiki" - unless exists $config{wikistatedir}; + unless exists $config{wikistatedir} && defined $config{wikistatedir}; if (defined $config{umask}) { umask(possibly_foolish_untaint($config{umask})); @@ -706,6 +721,10 @@ sub readfile ($;$$) { #{{{ binmode($in) if ($binary); return \*$in if $wantfd; my $ret=<$in>; + # check for invalid utf-8, and toss it back to avoid crashes + if (! utf8::valid($ret)) { + $ret=encode_utf8($ret); + } close $in || error("failed to read $file: $!"); return $ret; } #}}} @@ -898,6 +917,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) { @@ -1258,8 +1284,7 @@ sub indexlink () { #{{{ my $wikilock; -sub lockwiki (;$) { #{{{ - my $wait=@_ ? shift : 1; +sub lockwiki () { #{{{ # Take an exclusive lock on the wiki to prevent multiple concurrent # run issues. The lock will be dropped on program exit. if (! -d $config{wikistatedir}) { @@ -1267,25 +1292,14 @@ sub lockwiki (;$) { #{{{ } open($wikilock, '>', "$config{wikistatedir}/lockfile") || error ("cannot write to $config{wikistatedir}/lockfile: $!"); - if (! flock($wikilock, 2 | 4)) { # LOCK_EX | LOCK_NB - if ($wait) { - debug("wiki seems to be locked, waiting for lock"); - my $wait=600; # arbitrary, but don't hang forever to - # prevent process pileup - for (1..$wait) { - return if flock($wikilock, 2 | 4); - sleep 1; - } - error("wiki is locked; waited $wait seconds without lock being freed (possible stuck process or stale lock?)"); - } - else { - return 0; - } + if (! flock($wikilock, 2)) { # LOCK_EX + error("failed to get lock"); } return 1; } #}}} sub unlockwiki () { #{{{ + POSIX::close($ENV{IKIWIKI_CGILOCK_FD}) if exists $ENV{IKIWIKI_CGILOCK_FD}; return close($wikilock) if $wikilock; return; } #}}} @@ -1567,6 +1581,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); @@ -1659,6 +1677,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; @@ -1753,7 +1796,7 @@ sub pagespec_valid ($) { #{{{ my $sub=pagespec_translate($spec); return ! $@; } #}}} - + sub glob2re ($) { #{{{ my $re=quotemeta(shift); $re=~s/\\\*/.*/g; @@ -1850,6 +1893,10 @@ sub match_link ($$;@) { #{{{ else { return IkiWiki::SuccessReason->new("$page links to page $p matching $link") if match_glob($p, $link, %params); + $p=~s/^\///; + $link=~s/^\///; + return IkiWiki::SuccessReason->new("$page links to page $p matching $link") + if match_glob($p, $link, %params); } } return IkiWiki::FailReason->new("$page does not link to $link");