X-Git-Url: http://git.vanrenterghem.biz/git.ikiwiki.info.git/blobdiff_plain/678d467a4080dd549f2b6f276f963eac384e1b4f..968598b1bb333cc617f03948239aa9cba60566c3:/IkiWiki.pm diff --git a/IkiWiki.pm b/IkiWiki.pm index 759bfbc65..e260fffea 100644 --- a/IkiWiki.pm +++ b/IkiWiki.pm @@ -18,15 +18,15 @@ use vars qw{%config %links %oldlinks %pagemtime %pagectime %pagecase 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 newpagefile - inject + pagespec_match_list 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 = 3.00; # plugin interface version, next is ikiwiki version our $version='unknown'; # VERSION_AUTOREPLACE done by Makefile, DNE -my $installdir=''; # INSTALLDIR_AUTOREPLACE done by Makefile, DNE +our $installdir=''; # INSTALLDIR_AUTOREPLACE done by Makefile, DNE # Optimisation. use Memoize; @@ -174,7 +174,7 @@ sub getsetup () { verbose => { type => "boolean", example => 1, - description => "display verbose messages when building?", + description => "display verbose messages?", safe => 1, rebuild => 0, }, @@ -321,7 +321,7 @@ sub getsetup () { default => [qr/(^|\/)\.\.(\/|$)/, qr/^\./, qr/\/\./, qr/\.x?html?$/, qr/\.ikiwiki-new$/, qr/(^|\/).svn\//, qr/.arch-ids\//, qr/{arch}\//, - qr/(^|\/)_MTN\//, + qr/(^|\/)_MTN\//, qr/(^|\/)_darcs\//, qr/\.dpkg-tmp$/], description => "regexps of source files to ignore", safe => 0, @@ -533,7 +533,7 @@ sub loadplugins () { run_hooks(getopt => sub { shift->() }); if (grep /^-/, @ARGV) { - print STDERR "Unknown option: $_\n" + print STDERR "Unknown option (or missing parameter): $_\n" foreach grep /^-/, @ARGV; usage(); } @@ -627,27 +627,34 @@ sub dirname ($) { return $file; } -sub pagetype ($) { +sub isinternal ($) { my $page=shift; + return exists $pagesources{$page} && + $pagesources{$page} =~ /\._([^.]+)$/; +} + +sub pagetype ($) { + my $file=shift; - if ($page =~ /\.([^.]+)$/) { + if ($file =~ /\.([^.]+)$/) { return $1 if exists $hooks{htmlize}{$1}; } + my $base=basename($file); + if (exists $hooks{htmlize}{$base} && + $hooks{htmlize}{$base}{noextension}) { + return $base; + } return; } -sub isinternal ($) { - my $page=shift; - return exists $pagesources{$page} && - $pagesources{$page} =~ /\._([^.]+)$/; -} - sub pagename ($) { my $file=shift; my $type=pagetype($file); my $page=$file; - $page=~s/\Q.$type\E*$// if defined $type && !$hooks{htmlize}{$type}{keepextension}; + $page=~s/\Q.$type\E*$// + if defined $type && !$hooks{htmlize}{$type}{keepextension} + && !$hooks{htmlize}{$type}{noextension}; if ($config{indexpages} && $page=~/(.*)\/index$/) { $page=$1; } @@ -1293,6 +1300,70 @@ sub indexlink () { return "$config{wikiname}"; } +sub check_canedit ($$$;$) { + my $page=shift; + my $q=shift; + my $session=shift; + my $nonfatal=shift; + + my $canedit; + run_hooks(canedit => sub { + return if defined $canedit; + my $ret=shift->($page, $q, $session); + if (defined $ret) { + if ($ret eq "") { + $canedit=1; + } + elsif (ref $ret eq 'CODE') { + $ret->() unless $nonfatal; + $canedit=0; + } + elsif (defined $ret) { + error($ret) unless $nonfatal; + $canedit=0; + } + } + }); + return defined $canedit ? $canedit : 1; +} + +sub check_content (@) { + my %params=@_; + + return 1 if ! exists $hooks{checkcontent}; # optimisation + + if (exists $pagesources{$params{page}}) { + my @diff; + my %old=map { $_ => 1 } + split("\n", readfile(srcfile($pagesources{$params{page}}))); + foreach my $line (split("\n", $params{content})) { + push @diff, $line if ! exists $old{$_}; + } + $params{content}=join("\n", @diff); + } + + my $ok; + run_hooks(checkcontent => sub { + return if defined $ok; + my $ret=shift->(%params); + if (defined $ret) { + if ($ret eq "") { + $ok=1; + } + elsif (ref $ret eq 'CODE') { + $ret->() unless $params{nonfatal}; + $ok=0; + } + elsif (defined $ret) { + error($ret) unless $params{nonfatal}; + $ok=0; + } + } + + }); + return defined $ok ? $ok : 1; +} + my $wikilock; sub lockwiki () { @@ -1536,15 +1607,19 @@ sub run_hooks ($$) { my $sub=shift; if (exists $hooks{$type}) { - my @deferred; + my (@first, @middle, @last); foreach my $id (keys %{$hooks{$type}}) { - if ($hooks{$type}{$id}{last}) { - push @deferred, $id; - next; + if ($hooks{$type}{$id}{first}) { + push @first, $id; + } + elsif ($hooks{$type}{$id}{last}) { + push @last, $id; + } + else { + push @middle, $id; } - $sub->($hooks{$type}{$id}{call}); } - foreach my $id (@deferred) { + foreach my $id (@first, @middle, @last) { $sub->($hooks{$type}{$id}{call}); } } @@ -1596,37 +1671,6 @@ sub rcs_receive () { $hooks{rcs}{rcs_receive}{call}->(); } -sub globlist_to_pagespec ($) { - my @globlist=split(' ', shift); - - my (@spec, @skip); - foreach my $glob (@globlist) { - if ($glob=~/^!(.*)/) { - push @skip, $glob; - } - else { - push @spec, $glob; - } - } - - my $spec=join(' or ', @spec); - if (@skip) { - my $skip=join(' and ', @skip); - if (length $spec) { - $spec="$skip and ($spec)"; - } - else { - $spec=$skip; - } - } - return $spec; -} - -sub is_globlist ($) { - my $s=shift; - return ( $s =~ /[^\s]+\s+([^\s]+)/ && $1 ne "and" && $1 ne "or" ); -} - sub safequote ($) { my $s=shift; $s=~s/[{}]//g; @@ -1685,7 +1729,7 @@ sub gettext { sub yesno ($) { my $val=shift; - return (defined $val && lc($val) eq gettext("yes")); + return (defined $val && (lc($val) eq gettext("yes") || lc($val) eq "yes" || $val eq "1")); } sub inject { @@ -1718,26 +1762,12 @@ sub pagespec_merge ($$) { my $b=shift; return $a if $a eq $b; - - # Support for old-style GlobLists. - if (is_globlist($a)) { - $a=globlist_to_pagespec($a); - } - if (is_globlist($b)) { - $b=globlist_to_pagespec($b); - } - return "($a) or ($b)"; } sub pagespec_translate ($) { my $spec=shift; - # Support for old-style GlobLists. - if (is_globlist($spec)) { - $spec=globlist_to_pagespec($spec); - } - # Convert spec to perl code. my $code=""; while ($spec=~m{ @@ -1770,7 +1800,7 @@ sub pagespec_translate ($) { $code.="IkiWiki::PageSpec::match_$1(\$page, ".safequote($2).", \@_)"; } else { - $code.=' 0'; + $code.="IkiWiki::ErrorReason->new(".safequote(qq{unknown function in pagespec "$word"}).")"; } } else { @@ -1779,7 +1809,7 @@ sub pagespec_translate ($) { } if (! length $code) { - $code=0; + $code="IkiWiki::FailReason->new('empty pagespec')"; } no warnings; @@ -1797,11 +1827,35 @@ sub pagespec_match ($$;@) { } my $sub=pagespec_translate($spec); - return IkiWiki::FailReason->new("syntax error in pagespec \"$spec\"") + return IkiWiki::ErrorReason->new("syntax error in pagespec \"$spec\"") if $@ || ! defined $sub; return $sub->($page, @params); } +sub pagespec_match_list ($$;@) { + my $pages=shift; + my $spec=shift; + my @params=@_; + + my $sub=pagespec_translate($spec); + error "syntax error in pagespec \"$spec\"" + if $@ || ! defined $sub; + + my @ret; + my $r; + foreach my $page (@$pages) { + $r=$sub->($page, @params); + push @ret, $page if $r; + } + + if (! @ret && defined $r && $r->isa("IkiWiki::ErrorReason")) { + error(sprintf(gettext("cannot match pages: %s"), $r)); + } + else { + return @ret; + } +} + sub pagespec_valid ($) { my $spec=shift; @@ -1831,6 +1885,10 @@ sub new { return bless \$value, $class; } +package IkiWiki::ErrorReason; + +our @ISA = 'IkiWiki::FailReason'; + package IkiWiki::SuccessReason; use overload ( @@ -1848,19 +1906,25 @@ sub new { package IkiWiki::PageSpec; +sub derel ($$) { + my $path=shift; + my $from=shift; + + if ($path =~ m!^\./!) { + $from=~s#/?[^/]+$## if defined $from; + $path=~s#^\./##; + $path="$from/$path" if length $from; + } + + return $path; +} + sub match_glob ($$;@) { my $page=shift; my $glob=shift; my %params=@_; - my $from=exists $params{location} ? $params{location} : ''; - - # relative matching - if ($glob =~ m!^\./!) { - $from=~s#/?[^/]+$##; - $glob=~s#^\./##; - $glob="$from/$glob" if length $from; - } + $glob=derel($glob, $params{location}); my $regexp=IkiWiki::glob2re($glob); if ($page=~/^$regexp$/i) { @@ -1885,15 +1949,9 @@ sub match_link ($$;@) { my $link=lc(shift); my %params=@_; + $link=derel($link, $params{location}); my $from=exists $params{location} ? $params{location} : ''; - # relative matching - if ($link =~ m!^\.! && defined $from) { - $from=~s#/?[^/]+$##; - $link=~s#^\./##; - $link="$from/$link" if length $from; - } - my $links = $IkiWiki::links{$page}; return IkiWiki::FailReason->new("$page has no links") unless $links && @{$links}; my $bestlink = IkiWiki::bestlink($from, $link); @@ -1921,6 +1979,9 @@ sub match_backlink ($$;@) { sub match_created_before ($$;@) { my $page=shift; my $testpage=shift; + my %params=@_; + + $testpage=derel($testpage, $params{location}); if (exists $IkiWiki::pagectime{$testpage}) { if ($IkiWiki::pagectime{$page} < $IkiWiki::pagectime{$testpage}) { @@ -1938,6 +1999,9 @@ sub match_created_before ($$;@) { sub match_created_after ($$;@) { my $page=shift; my $testpage=shift; + my %params=@_; + + $testpage=derel($testpage, $params{location}); if (exists $IkiWiki::pagectime{$testpage}) { if ($IkiWiki::pagectime{$page} > $IkiWiki::pagectime{$testpage}) { @@ -1985,7 +2049,7 @@ sub match_user ($$;@) { my %params=@_; if (! exists $params{user}) { - return IkiWiki::FailReason->new("no user specified"); + return IkiWiki::ErrorReason->new("no user specified"); } if (defined $params{user} && lc $params{user} eq lc $user) { @@ -2005,7 +2069,7 @@ sub match_admin ($$;@) { my %params=@_; if (! exists $params{user}) { - return IkiWiki::FailReason->new("no user specified"); + return IkiWiki::ErrorReason->new("no user specified"); } if (defined $params{user} && IkiWiki::is_admin($params{user})) { @@ -2025,7 +2089,7 @@ sub match_ip ($$;@) { my %params=@_; if (! exists $params{ip}) { - return IkiWiki::FailReason->new("no IP specified"); + return IkiWiki::ErrorReason->new("no IP specified"); } if (defined $params{ip} && lc $params{ip} eq lc $ip) {