X-Git-Url: http://git.vanrenterghem.biz/git.ikiwiki.info.git/blobdiff_plain/040038b6559140b4a8c04396098ade2b4d4573b9..92821be5402cd2fa74a037cb28619ee4a7a2e6e1:/IkiWiki.pm
diff --git a/IkiWiki.pm b/IkiWiki.pm
index 799236f35..e5da04a3b 100644
--- a/IkiWiki.pm
+++ b/IkiWiki.pm
@@ -14,15 +14,15 @@ use vars qw{%config %links %oldlinks %pagemtime %pagectime %pagecase
%pagestate %wikistate %renderedfiles %oldrenderedfiles
%pagesources %delpagesources %destsources %depends %depends_simple
@mass_depends %hooks %forcerebuild %loaded_plugins %typedlinks
- %oldtypedlinks %autofiles};
+ %oldtypedlinks %autofiles @underlayfiles $lastrev};
use Exporter q{import};
our @EXPORT = qw(hook debug error htmlpage template template_depends
deptype add_depends pagespec_match pagespec_match_list bestlink
htmllink readfile writefile pagetype srcfile pagename
- displaytime will_render gettext ngettext urlto targetpage
+ displaytime strftime_utf8 will_render gettext ngettext urlto targetpage
add_underlay pagetitle titlepage linkpage newpagefile
- inject add_link add_autofile
+ inject add_link add_autofile useragent
%config %links %pagestate %wikistate %renderedfiles
%pagesources %destsources %typedlinks);
our $VERSION = 3.00; # plugin interface version, next is ikiwiki version
@@ -118,6 +118,29 @@ sub getsetup () {
safe => 0,
rebuild => 0,
},
+ cgi_overload_delay => {
+ type => "string",
+ default => '',
+ example => "10",
+ description => "number of seconds to delay CGI requests when overloaded",
+ safe => 1,
+ rebuild => 0,
+ },
+ cgi_overload_message => {
+ type => "string",
+ default => '',
+ example => "Please wait",
+ description => "message to display when overloaded (may contain html)",
+ safe => 1,
+ rebuild => 0,
+ },
+ only_committed_changes => {
+ type => "boolean",
+ default => 0,
+ description => "enable optimization of only refreshing committed changes?",
+ safe => 1,
+ rebuild => 0,
+ },
rcs => {
type => "string",
default => '',
@@ -237,8 +260,8 @@ sub getsetup () {
html5 => {
type => "boolean",
default => 0,
- description => "generate HTML5? (experimental)",
- advanced => 1,
+ description => "generate HTML5?",
+ advanced => 0,
safe => 1,
rebuild => 1,
},
@@ -305,9 +328,9 @@ sub getsetup () {
rebuild => 0,
},
umask => {
- type => "integer",
- example => "022",
- description => "force ikiwiki to use a particular umask",
+ type => "string",
+ example => "public",
+ description => "force ikiwiki to use a particular umask (keywords public, group or private, or a number)",
advanced => 1,
safe => 0, # paranoia
rebuild => 0,
@@ -336,6 +359,14 @@ sub getsetup () {
safe => 0, # paranoia
rebuild => 0,
},
+ timezone => {
+ type => "string",
+ default => "",
+ example => "US/Eastern",
+ description => "time zone name",
+ safe => 1,
+ rebuild => 1,
+ },
include => {
type => "string",
default => undef,
@@ -477,7 +508,7 @@ sub getsetup () {
},
setuptype => {
type => "internal",
- default => "Standard",
+ default => "Yaml",
description => "perl class to use to dump setup file",
safe => 0,
rebuild => 0,
@@ -489,6 +520,21 @@ sub getsetup () {
safe => 0,
rebuild => 0,
},
+ cookiejar => {
+ type => "string",
+ default => { file => "$ENV{HOME}/.ikiwiki/cookies" },
+ description => "cookie control",
+ safe => 0, # hooks into perl module internals
+ rebuild => 0,
+ },
+ useragent => {
+ type => "string",
+ default => undef,
+ example => "Wget/1.13.4 (linux-gnu)",
+ description => "set custom user agent string for outbound HTTP requests e.g. when fetching aggregated RSS feeds",
+ safe => 0,
+ rebuild => 0,
+ },
}
sub defaultconfig () {
@@ -497,7 +543,6 @@ sub defaultconfig () {
foreach my $key (keys %s) {
push @ret, $key, $s{$key}->{default};
}
- use Data::Dumper;
return @ret;
}
@@ -529,6 +574,12 @@ sub checkconfig () {
$ENV{$val}=$config{ENV}{$val};
}
}
+ if (defined $config{timezone} && length $config{timezone}) {
+ $ENV{TZ}=$config{timezone};
+ }
+ else {
+ $config{timezone}=$ENV{TZ};
+ }
if ($config{w3mmode}) {
eval q{use Cwd q{abs_path}};
@@ -574,7 +625,23 @@ sub checkconfig () {
unless exists $config{wikistatedir} && defined $config{wikistatedir};
if (defined $config{umask}) {
- umask(possibly_foolish_untaint($config{umask}));
+ my $u = possibly_foolish_untaint($config{umask});
+
+ if ($u =~ m/^\d+$/) {
+ umask($u);
+ }
+ elsif ($u eq 'private') {
+ umask(077);
+ }
+ elsif ($u eq 'group') {
+ umask(027);
+ }
+ elsif ($u eq 'public') {
+ umask(022);
+ }
+ else {
+ error(sprintf(gettext("unsupported umask setting %s"), $u));
+ }
}
run_hooks(checkconfig => sub { shift->() });
@@ -676,6 +743,7 @@ sub debug ($) {
}
my $log_open=0;
+my $log_failed=0;
sub log_message ($$) {
my $type=shift;
@@ -686,9 +754,18 @@ sub log_message ($$) {
Sys::Syslog::openlog('ikiwiki', '', 'user');
$log_open=1;
}
- return eval {
- Sys::Syslog::syslog($type, "[$config{wikiname}] %s", join(" ", @_));
+ eval {
+ # keep a copy to avoid editing the original config repeatedly
+ my $wikiname = $config{wikiname};
+ utf8::encode($wikiname);
+ Sys::Syslog::syslog($type, "[$wikiname] %s", join(" ", @_));
};
+ if ($@) {
+ print STDERR "failed to syslog: $@" unless $log_failed;
+ $log_failed=1;
+ print STDERR "@_\n";
+ }
+ return $@;
}
elsif (! $config{cgi}) {
return print "@_\n";
@@ -810,17 +887,23 @@ sub srcfile ($;$) {
return (srcfile_stat(@_))[0];
}
-sub add_underlay ($) {
+sub add_literal_underlay ($) {
my $dir=shift;
- if ($dir !~ /^\//) {
- $dir="$config{underlaydirbase}/$dir";
- }
-
if (! grep { $_ eq $dir } @{$config{underlaydirs}}) {
unshift @{$config{underlaydirs}}, $dir;
}
+}
+
+sub add_underlay ($) {
+ my $dir = shift;
+ if ($dir !~ /^\//) {
+ $dir="$config{underlaydirbase}/$dir";
+ }
+
+ add_literal_underlay($dir);
+ # why does it return 1? we just don't know
return 1;
}
@@ -1007,7 +1090,7 @@ sub bestlink ($$) {
sub isinlinableimage ($) {
my $file=shift;
- return $file =~ /\.(png|gif|jpg|jpeg)$/i;
+ return $file =~ /\.(png|gif|jpg|jpeg|svg)$/i;
}
sub pagetitle ($;$) {
@@ -1057,6 +1140,11 @@ sub cgiurl (@) {
join("&", map $_."=".uri_escape_utf8($params{$_}), keys %params);
}
+sub cgiurl_abs (@) {
+ eval q{use URI};
+ URI->new_abs(cgiurl(@_), $config{cgiurl});
+}
+
sub baseurl (;$) {
my $page=shift;
@@ -1113,9 +1201,19 @@ sub formattime ($;$) {
$format=$config{timeformat};
}
+ return strftime_utf8($format, localtime($time));
+}
+
+my $strftime_encoding;
+sub strftime_utf8 {
# strftime doesn't know about encodings, so make sure
- # its output is properly treated as utf8
- return decode_utf8(POSIX::strftime($format, localtime($time)));
+ # its output is properly treated as utf8.
+ # Note that this does not handle utf-8 in the format string.
+ ($strftime_encoding) = POSIX::setlocale(&POSIX::LC_TIME) =~ m#\.([^@]+)#
+ unless defined $strftime_encoding;
+ $strftime_encoding
+ ? Encode::decode($strftime_encoding, POSIX::strftime(@_))
+ : POSIX::strftime(@_);
}
sub date_3339 ($) {
@@ -1162,7 +1260,7 @@ sub urlto ($;$$) {
}
if (! defined $from) {
- my $u = $local_url;
+ my $u = $local_url || '';
$u =~ s{/$}{};
return $u.beautify_urlpath("/".$to);
}
@@ -1218,7 +1316,7 @@ sub htmllink ($$$;@) {
$cgilink = " "create",
- page => lc($link),
+ page => $link,
from => $lpage
)."\" rel=\"nofollow\">?";
}
@@ -1367,16 +1465,21 @@ sub preprocess ($$$;$$) {
# consider it significant.
my @params;
while ($params =~ m{
- (?:([-\w]+)=)? # 1: named parameter key?
+ (?:([-.\w]+)=)? # 1: named parameter key?
(?:
"""(.*?)""" # 2: triple-quoted value
|
"([^"]*?)" # 3: single-quoted value
|
- (\S+) # 4: unquoted value
+ '''(.*?)''' # 4: triple-single-quote
+ |
+ <<([a-zA-Z]+)\n # 5: heredoc start
+ (.*?)\n\5 # 6: heredoc value
+ |
+ (\S+) # 7: unquoted value
)
(?:\s+|$) # delimiter to next param
- }sgx) {
+ }msgx) {
my $key=$1;
my $val;
if (defined $2) {
@@ -1391,6 +1494,12 @@ sub preprocess ($$$;$$) {
elsif (defined $4) {
$val=$4;
}
+ elsif (defined $7) {
+ $val=$7;
+ }
+ elsif (defined $6) {
+ $val=$6;
+ }
if (defined $key) {
push @params, $key, $val;
@@ -1399,7 +1508,7 @@ sub preprocess ($$$;$$) {
push @params, $val, '';
}
}
- if ($preprocessing{$page}++ > 3) {
+ if ($preprocessing{$page}++ > 8) {
# Avoid loops of preprocessed pages preprocessing
# other pages that preprocess them, etc.
return "[[!$command ".
@@ -1453,12 +1562,17 @@ sub preprocess ($$$;$$) {
( # 4: the parameters..
\s+ # Must have space if parameters present
(?:
- (?:[-\w]+=)? # named parameter key?
+ (?:[-.\w]+=)? # named parameter key?
(?:
""".*?""" # triple-quoted value
|
"[^"]*?" # single-quoted value
|
+ '''.*?''' # triple-single-quote
+ |
+ <<([a-zA-Z]+)\n # 5: heredoc start
+ (?:.*?)\n\5 # heredoc value
+ |
[^"\s\]]+ # unquoted value
)
\s* # whitespace or end
@@ -1476,12 +1590,17 @@ sub preprocess ($$$;$$) {
\s+
( # 4: the parameters..
(?:
- (?:[-\w]+=)? # named parameter key?
+ (?:[-.\w]+=)? # named parameter key?
(?:
""".*?""" # triple-quoted value
|
"[^"]*?" # single-quoted value
|
+ '''.*?''' # triple-single-quote
+ |
+ <<([a-zA-Z]+)\n # 5: heredoc start
+ (?:.*?)\n\5 # heredoc value
+ |
[^"\s\]]+ # unquoted value
)
\s* # whitespace or end
@@ -1687,7 +1806,8 @@ sub enable_commit_hook () {
sub loadindex () {
%oldrenderedfiles=%pagectime=();
- if (! $config{rebuild}) {
+ my $rebuild=$config{rebuild};
+ if (! $rebuild) {
%pagesources=%pagemtime=%oldlinks=%links=%depends=
%destsources=%renderedfiles=%pagecase=%pagestate=
%depends_simple=%typedlinks=%oldtypedlinks=();
@@ -1727,10 +1847,16 @@ sub loadindex () {
foreach my $src (keys %$pages) {
my $d=$pages->{$src};
- my $page=pagename($src);
+ my $page;
+ if (exists $d->{page} && ! $rebuild) {
+ $page=$d->{page};
+ }
+ else {
+ $page=pagename($src);
+ }
$pagectime{$page}=$d->{ctime};
$pagesources{$page}=$src;
- if (! $config{rebuild}) {
+ if (! $rebuild) {
$pagemtime{$page}=$d->{mtime};
$renderedfiles{$page}=$d->{dest};
if (exists $d->{links} && ref $d->{links}) {
@@ -1780,6 +1906,8 @@ sub loadindex () {
foreach my $page (keys %renderedfiles) {
$destsources{$_}=$page foreach @{$renderedfiles{$page}};
}
+ $lastrev=$index->{lastrev};
+ @underlayfiles=@{$index->{underlayfiles}} if ref $index->{underlayfiles};
return close($in);
}
@@ -1801,6 +1929,7 @@ sub saveindex () {
my $src=$pagesources{$page};
$index{page}{$src}={
+ page => $page,
ctime => $pagectime{$page},
mtime => $pagemtime{$page},
dest => $renderedfiles{$page},
@@ -1820,11 +1949,7 @@ sub saveindex () {
}
if (exists $pagestate{$page}) {
- foreach my $id (@plugins) {
- foreach my $key (keys %{$pagestate{$page}{$id}}) {
- $index{page}{$src}{state}{$id}{$key}=$pagestate{$page}{$id}{$key};
- }
- }
+ $index{page}{$src}{state}=$pagestate{$page};
}
}
@@ -1836,6 +1961,9 @@ sub saveindex () {
}
}
+ $index{lastrev}=$lastrev;
+ $index{underlayfiles}=\@underlayfiles;
+
$index{version}="3";
my $ret=Storable::nstore_fd(\%index, $out);
return if ! defined $ret || ! $ret;
@@ -2187,6 +2315,14 @@ sub add_autofile ($$$) {
$autofiles{$file}{generator}=$generator;
}
+sub useragent () {
+ return LWP::UserAgent->new(
+ cookie_jar => $config{cookiejar},
+ env_proxy => 1, # respect proxy env vars
+ agent => $config{useragent},
+ );
+}
+
sub sortspec_translate ($$) {
my $spec = shift;
my $reverse = shift;
@@ -2591,8 +2727,14 @@ sub match_link ($$;@) {
}
sub match_backlink ($$;@) {
- my $ret=match_link($_[1], $_[0], @_);
- $ret->influences($_[1] => $IkiWiki::DEPEND_LINKS);
+ my $page=shift;
+ my $testpage=shift;
+ my %params=@_;
+ if ($testpage eq '.') {
+ $testpage = $params{'location'}
+ }
+ my $ret=match_link($testpage, $page, @_);
+ $ret->influences($testpage => $IkiWiki::DEPEND_LINKS);
return $ret;
}
@@ -2683,12 +2825,12 @@ sub match_user ($$;@) {
my $user=shift;
my %params=@_;
- my $regexp=IkiWiki::glob2re($user);
-
if (! exists $params{user}) {
return IkiWiki::ErrorReason->new("no user specified");
}
+ my $regexp=IkiWiki::glob2re($user);
+
if (defined $params{user} && $params{user}=~$regexp) {
return IkiWiki::SuccessReason->new("user is $user");
}
@@ -2728,8 +2870,10 @@ sub match_ip ($$;@) {
if (! exists $params{ip}) {
return IkiWiki::ErrorReason->new("no IP specified");
}
+
+ my $regexp=IkiWiki::glob2re(lc $ip);
- if (defined $params{ip} && lc $params{ip} eq lc $ip) {
+ if (defined $params{ip} && lc $params{ip}=~$regexp) {
return IkiWiki::SuccessReason->new("IP is $ip");
}
else {
@@ -2752,6 +2896,7 @@ sub cmp_title {
IkiWiki::pagetitle(IkiWiki::basename($b))
}
+sub cmp_path { IkiWiki::pagetitle($a) cmp IkiWiki::pagetitle($b) }
sub cmp_mtime { $IkiWiki::pagemtime{$b} <=> $IkiWiki::pagemtime{$a} }
sub cmp_age { $IkiWiki::pagectime{$b} <=> $IkiWiki::pagectime{$a} }