summaryrefslogtreecommitdiff
path: root/IkiWiki
diff options
context:
space:
mode:
Diffstat (limited to 'IkiWiki')
-rw-r--r--IkiWiki/CGI.pm99
-rw-r--r--IkiWiki/Plugin/aggregate.pm3
-rw-r--r--IkiWiki/Plugin/calendar.pm3
-rw-r--r--IkiWiki/Plugin/ddate.pm6
-rw-r--r--IkiWiki/Plugin/edittemplate.pm3
-rw-r--r--IkiWiki/Plugin/inline.pm2
-rw-r--r--IkiWiki/Plugin/meta.pm125
-rw-r--r--IkiWiki/Plugin/prettydate.pm5
-rw-r--r--IkiWiki/Plugin/recentchanges.pm116
-rw-r--r--IkiWiki/Plugin/version.pm3
-rw-r--r--IkiWiki/Rcs/Stub.pm8
-rw-r--r--IkiWiki/Rcs/git.pm48
-rw-r--r--IkiWiki/Rcs/mercurial.pm6
-rw-r--r--IkiWiki/Rcs/monotone.pm50
-rw-r--r--IkiWiki/Rcs/svn.pm43
-rw-r--r--IkiWiki/Rcs/tla.pm50
-rw-r--r--IkiWiki/Render.pm61
-rw-r--r--IkiWiki/UserInfo.pm87
-rw-r--r--IkiWiki/Wrapper.pm16
19 files changed, 283 insertions, 451 deletions
diff --git a/IkiWiki/CGI.pm b/IkiWiki/CGI.pm
index 65a1d7fa0..c8c1b63dd 100644
--- a/IkiWiki/CGI.pm
+++ b/IkiWiki/CGI.pm
@@ -84,53 +84,6 @@ sub decode_cgi_utf8 ($) { #{{{
}
} #}}}
-sub cgi_recentchanges ($) { #{{{
- my $q=shift;
-
- # Optimisation: building recentchanges means calculating lots of
- # links. Memoizing htmllink speeds it up a lot (can't be memoized
- # during page builds as the return values may change, but they
- # won't here.)
- eval q{use Memoize};
- error($@) if $@;
- memoize("htmllink");
-
- eval q{use Time::Duration};
- error($@) if $@;
-
- my $changelog=[rcs_recentchanges(100)];
- foreach my $change (@$changelog) {
- $change->{when} = concise(ago($change->{when}));
-
- $change->{user} = userlink($change->{user});
-
- my $is_excess = exists $change->{pages}[10]; # limit pages to first 10
- delete @{$change->{pages}}[10 .. @{$change->{pages}}] if $is_excess;
- $change->{pages} = [
- map {
- $_->{link} = htmllink("", "", $_->{page},
- noimageinline => 1,
- linktext => pagetitle($_->{page}));
- $_;
- } @{$change->{pages}}
- ];
- push @{$change->{pages}}, { link => '...' } if $is_excess;
- }
-
- my $template=template("recentchanges.tmpl");
- $template->param(
- title => "RecentChanges",
- indexlink => indexlink(),
- wikiname => $config{wikiname},
- changelog => $changelog,
- baseurl => baseurl(),
- );
- run_hooks(pagetemplate => sub {
- shift->(page => "", destpage => "", template => $template);
- });
- print $q->header(-charset => 'utf-8'), $template->output;
-} #}}}
-
# Check if the user is signed in. If not, redirect to the signin form and
# save their place to return to later.
sub needsignin ($$) { #{{{
@@ -242,9 +195,6 @@ sub cgi_prefs ($$) { #{{{
$form->field(name => "do", type => "hidden");
$form->field(name => "email", size => 50, fieldset => "preferences");
- $form->field(name => "subscriptions", size => 50,
- fieldset => "preferences",
- comment => "(".htmllink("", "", "ikiwiki/PageSpec", noimageinline => 1).")");
$form->field(name => "banned_users", size => 50,
fieldset => "admin");
@@ -256,8 +206,6 @@ sub cgi_prefs ($$) { #{{{
if (! $form->submitted) {
$form->field(name => "email", force => 1,
value => userinfo_get($user_name, "email"));
- $form->field(name => "subscriptions", force => 1,
- value => userinfo_get($user_name, "subscriptions"));
if (is_admin($user_name)) {
$form->field(name => "banned_users", force => 1,
value => join(" ", get_banned_users()));
@@ -274,11 +222,9 @@ sub cgi_prefs ($$) { #{{{
return;
}
elsif ($form->submitted eq 'Save Preferences' && $form->validate) {
- foreach my $field (qw(email subscriptions)) {
- if (defined $form->field($field)) {
- userinfo_set($user_name, $field, $form->field($field)) ||
- error("failed to set $field");
- }
+ if (defined $form->field('email')) {
+ userinfo_set($user_name, 'email', $form->field('email')) ||
+ error("failed to set email");
}
if (is_admin($user_name)) {
set_banned_users(grep { ! is_admin($_) }
@@ -341,7 +287,7 @@ sub cgi_editpage ($$) { #{{{
if (exists $pagesources{$page} && $form->field("do") ne "create") {
$file=$pagesources{$page};
$type=pagetype($file);
- if (! defined $type) {
+ if (! defined $type || $type=~/^_/) {
error(sprintf(gettext("%s is not an editable page"), $page));
}
if (! $form->submitted) {
@@ -470,7 +416,8 @@ sub cgi_editpage ($$) { #{{{
my @page_types;
if (exists $hooks{htmlize}) {
- @page_types=keys %{$hooks{htmlize}};
+ @page_types=grep { !/^_/ }
+ keys %{$hooks{htmlize}};
}
$form->tmpl_param("page_select", 1);
@@ -667,12 +614,6 @@ sub cgi (;$$) { #{{{
}
}
- # Things that do not need a session.
- if ($do eq 'recentchanges') {
- cgi_recentchanges($q);
- return;
- }
-
# Need to lock the wiki before getting a session.
lockwiki();
@@ -726,32 +667,4 @@ sub cgi (;$$) { #{{{
}
} #}}}
-sub userlink ($) { #{{{
- my $user=shift;
-
- eval q{use CGI 'escapeHTML'};
- error($@) if $@;
- if ($user =~ m!^https?://! &&
- eval q{use Net::OpenID::VerifiedIdentity; 1} && !$@) {
- # Munge user-urls, as used by eg, OpenID.
- my $oid=Net::OpenID::VerifiedIdentity->new(identity => $user);
- my $display=$oid->display;
- # Convert "user.somehost.com" to "user [somehost.com]".
- if ($display !~ /\[/) {
- $display=~s/^(.*?)\.([^.]+\.[a-z]+)$/$1 [$2]/;
- }
- # Convert "http://somehost.com/user" to "user [somehost.com]".
- if ($display !~ /\[/) {
- $display=~s/^https?:\/\/(.+)\/([^\/]+)$/$2 [$1]/;
- }
- $display=~s!^https?://!!; # make sure this is removed
- return "<a href=\"$user\">".escapeHTML($display)."</a>";
- }
- else {
- return htmllink("", "", escapeHTML(
- length $config{userdir} ? $config{userdir}."/".$user : $user
- ), noimageinline => 1);
- }
-} #}}}
-
1
diff --git a/IkiWiki/Plugin/aggregate.pm b/IkiWiki/Plugin/aggregate.pm
index 71368e254..2a4d10411 100644
--- a/IkiWiki/Plugin/aggregate.pm
+++ b/IkiWiki/Plugin/aggregate.pm
@@ -66,7 +66,8 @@ sub needsbuild (@) { #{{{
loadstate(); # if not already loaded
foreach my $feed (values %feeds) {
- if (grep { $_ eq $pagesources{$feed->{sourcepage}} } @$needsbuild) {
+ if (exists $pagesources{$feed->{sourcepage}} &&
+ grep { $_ eq $pagesources{$feed->{sourcepage}} } @$needsbuild) {
# Mark all feeds originating on this page as removable;
# preprocess will unmark those that still exist.
remove_feeds($feed->{sourcepage});
diff --git a/IkiWiki/Plugin/calendar.pm b/IkiWiki/Plugin/calendar.pm
index 4bb4c2c21..aed087eed 100644
--- a/IkiWiki/Plugin/calendar.pm
+++ b/IkiWiki/Plugin/calendar.pm
@@ -390,7 +390,8 @@ sub needsbuild (@) { #{{{
# the current day
push @$needsbuild, $pagesources{$page};
}
- if (grep { $_ eq $pagesources{$page} } @$needsbuild) {
+ if (exists $pagesources{$page} &&
+ grep { $_ eq $pagesources{$page} } @$needsbuild) {
# remove state, will be re-added if
# the calendar is still there during the
# rebuild
diff --git a/IkiWiki/Plugin/ddate.pm b/IkiWiki/Plugin/ddate.pm
index 6b67f4202..d081cb509 100644
--- a/IkiWiki/Plugin/ddate.pm
+++ b/IkiWiki/Plugin/ddate.pm
@@ -18,6 +18,10 @@ sub checkconfig () { #{{{
sub IkiWiki::displaytime ($;$) { #{{{
my $time=shift;
+ my $format=shift;
+ if (! defined $format) {
+ $format=$config{timeformat};
+ }
eval q{
use DateTime;
use DateTime::Calendar::Discordian;
@@ -27,7 +31,7 @@ sub IkiWiki::displaytime ($;$) { #{{{
}
my $dt = DateTime->from_epoch(epoch => $time);
my $dd = DateTime::Calendar::Discordian->from_object(object => $dt);
- return $dd->strftime($IkiWiki::config{timeformat});
+ return $dd->strftime($format);
} #}}}
5
diff --git a/IkiWiki/Plugin/edittemplate.pm b/IkiWiki/Plugin/edittemplate.pm
index aa72b0845..b7651ce02 100644
--- a/IkiWiki/Plugin/edittemplate.pm
+++ b/IkiWiki/Plugin/edittemplate.pm
@@ -21,7 +21,8 @@ sub needsbuild (@) { #{{{
foreach my $page (keys %pagestate) {
if (exists $pagestate{$page}{edittemplate}) {
- if (grep { $_ eq $pagesources{$page} } @$needsbuild) {
+ if (exists $pagesources{$page} &&
+ grep { $_ eq $pagesources{$page} } @$needsbuild) {
# remove state, it will be re-added
# if the preprocessor directive is still
# there during the rebuild
diff --git a/IkiWiki/Plugin/inline.pm b/IkiWiki/Plugin/inline.pm
index 59eabb606..796cf2cf6 100644
--- a/IkiWiki/Plugin/inline.pm
+++ b/IkiWiki/Plugin/inline.pm
@@ -231,6 +231,8 @@ sub preprocess_inline (@) { #{{{
$template->param(pageurl => urlto(bestlink($params{page}, $page), $params{destpage}));
$template->param(title => pagetitle(basename($page)));
$template->param(ctime => displaytime($pagectime{$page}, $params{timeformat}));
+ $template->param(first => 1) if $page eq $list[0];
+ $template->param(last => 1) if $page eq $list[$#list];
if ($actions) {
my $file = $pagesources{$page};
diff --git a/IkiWiki/Plugin/meta.pm b/IkiWiki/Plugin/meta.pm
index d2c6e7f8b..621e87674 100644
--- a/IkiWiki/Plugin/meta.pm
+++ b/IkiWiki/Plugin/meta.pm
@@ -6,13 +6,7 @@ use warnings;
use strict;
use IkiWiki 2.00;
-my %meta;
-my %title;
-my %permalink;
-my %author;
-my %authorurl;
-my %license;
-my %copyright;
+my %metaheaders;
sub import { #{{{
hook(type => "needsbuild", id => "meta", call => \&needsbuild);
@@ -24,7 +18,8 @@ sub needsbuild (@) { #{{{
my $needsbuild=shift;
foreach my $page (keys %pagestate) {
if (exists $pagestate{$page}{meta}) {
- if (grep { $_ eq $pagesources{$page} } @$needsbuild) {
+ if (exists $pagesources{$page} &&
+ grep { $_ eq $pagesources{$page} } @$needsbuild) {
# remove state, it will be re-added
# if the preprocessor directive is still
# there during the rebuild
@@ -71,16 +66,16 @@ sub preprocess (@) { #{{{
# Metadata collection that needs to happen during the scan pass.
if ($key eq 'title') {
- $title{$page}=HTML::Entities::encode_numeric($value);
+ $pagestate{$page}{meta}{title}=HTML::Entities::encode_numeric($value);
}
elsif ($key eq 'license') {
- push @{$meta{$page}}, '<link rel="license" href="#page_license" />';
- $license{$page}=$value;
+ push @{$metaheaders{$page}}, '<link rel="license" href="#page_license" />';
+ $pagestate{$page}{meta}{license}=$value;
return "";
}
elsif ($key eq 'copyright') {
- push @{$meta{$page}}, '<link rel="copyright" href="#page_copyright" />';
- $copyright{$page}=$value;
+ push @{$metaheaders{$page}}, '<link rel="copyright" href="#page_copyright" />';
+ $pagestate{$page}{meta}{copyright}=$value;
return "";
}
elsif ($key eq 'link' && ! %params) {
@@ -89,11 +84,11 @@ sub preprocess (@) { #{{{
return "";
}
elsif ($key eq 'author') {
- $author{$page}=$value;
+ $pagestate{$page}{meta}{author}=$value;
# fallthorough
}
elsif ($key eq 'authorurl') {
- $authorurl{$page}=$value;
+ $pagestate{$page}{meta}{authorurl}=$value;
# fallthrough
}
@@ -111,8 +106,8 @@ sub preprocess (@) { #{{{
}
}
elsif ($key eq 'permalink') {
- $permalink{$page}=$value;
- push @{$meta{$page}}, scrub('<link rel="bookmark" href="'.encode_entities($value).'" />');
+ $pagestate{$page}{meta}{permalink}=$value;
+ push @{$metaheaders{$page}}, scrub('<link rel="bookmark" href="'.encode_entities($value).'" />');
}
elsif ($key eq 'stylesheet') {
my $rel=exists $params{rel} ? $params{rel} : "alternate stylesheet";
@@ -123,17 +118,17 @@ sub preprocess (@) { #{{{
if (! length $stylesheet) {
return "[[meta ".gettext("stylesheet not found")."]]";
}
- push @{$meta{$page}}, '<link href="'.urlto($stylesheet, $page).
+ push @{$metaheaders{$page}}, '<link href="'.urlto($stylesheet, $page).
'" rel="'.encode_entities($rel).
'" title="'.encode_entities($title).
"\" type=\"text/css\" />";
}
elsif ($key eq 'openid') {
if (exists $params{server}) {
- push @{$meta{$page}}, '<link href="'.encode_entities($params{server}).
+ push @{$metaheaders{$page}}, '<link href="'.encode_entities($params{server}).
'" rel="openid.server" />';
}
- push @{$meta{$page}}, '<link href="'.encode_entities($value).
+ push @{$metaheaders{$page}}, '<link href="'.encode_entities($value).
'" rel="openid.delegate" />';
}
elsif ($key eq 'redir') {
@@ -172,11 +167,11 @@ sub preprocess (@) { #{{{
if (! $safe) {
$redir=scrub($redir);
}
- push @{$meta{$page}}, $redir;
+ push @{$metaheaders{$page}}, $redir;
}
elsif ($key eq 'link') {
if (%params) {
- push @{$meta{$page}}, scrub("<link href=\"".encode_entities($value)."\" ".
+ push @{$metaheaders{$page}}, scrub("<link href=\"".encode_entities($value)."\" ".
join(" ", map {
encode_entities($_)."=\"".encode_entities(decode_entities($params{$_}))."\""
} keys %params).
@@ -184,7 +179,7 @@ sub preprocess (@) { #{{{
}
}
else {
- push @{$meta{$page}}, scrub('<meta name="'.encode_entities($key).
+ push @{$metaheaders{$page}}, scrub('<meta name="'.encode_entities($key).
'" content="'.encode_entities($value).'" />');
}
@@ -197,32 +192,80 @@ sub pagetemplate (@) { #{{{
my $destpage=$params{destpage};
my $template=$params{template};
- if (exists $meta{$page} && $template->query(name => "meta")) {
+ if (exists $metaheaders{$page} && $template->query(name => "meta")) {
# avoid duplicate meta lines
my %seen;
- $template->param(meta => join("\n", grep { (! $seen{$_}) && ($seen{$_}=1) } @{$meta{$page}}));
+ $template->param(meta => join("\n", grep { (! $seen{$_}) && ($seen{$_}=1) } @{$metaheaders{$page}}));
}
- if (exists $title{$page} && $template->query(name => "title")) {
- $template->param(title => $title{$page});
+ if (exists $pagestate{$page}{meta}{title} && $template->query(name => "title")) {
+ $template->param(title => $pagestate{$page}{meta}{title});
$template->param(title_overridden => 1);
}
- $template->param(permalink => $permalink{$page})
- if exists $permalink{$page} && $template->query(name => "permalink");
- $template->param(author => $author{$page})
- if exists $author{$page} && $template->query(name => "author");
- $template->param(authorurl => $authorurl{$page})
- if exists $authorurl{$page} && $template->query(name => "authorurl");
- if (exists $license{$page} && $template->query(name => "license") &&
- ($page eq $destpage || ! exists $license{$destpage} ||
- $license{$page} ne $license{$destpage})) {
- $template->param(license => htmlize($page, $destpage, $license{$page}));
+ foreach my $field (qw{author authorurl permalink}) {
+ $template->param($field => $pagestate{$page}{meta}{$field})
+ if exists $pagestate{$page}{meta}{$field} && $template->query(name => $field);
}
- if (exists $copyright{$page} && $template->query(name => "copyright") &&
- ($page eq $destpage || ! exists $copyright{$destpage} ||
- $copyright{$page} ne $copyright{$destpage})) {
- $template->param(copyright => htmlize($page, $destpage, $copyright{$page}));
+
+ foreach my $field (qw{license copyright}) {
+ if (exists $pagestate{$page}{meta}{$field} && $template->query(name => $field) &&
+ ($page eq $destpage || ! exists $pagestate{$destpage}{meta}{$field} ||
+ $pagestate{$page}{meta}{$field} ne $pagestate{$destpage}{meta}{$field})) {
+ $template->param($field => htmlize($page, $destpage, $pagestate{$page}{meta}{$field}));
+ }
}
} # }}}
+sub match { #{{{
+ my $field=shift;
+ my $page=shift;
+
+ # turn glob into a safe regexp
+ my $re=quotemeta(shift);
+ $re=~s/\\\*/.*/g;
+ $re=~s/\\\?/./g;
+
+ my $val;
+ if (exists $pagestate{$page}{meta}{$field}) {
+ $val=$pagestate{$page}{meta}{$field};
+ }
+ elsif ($field eq 'title') {
+ $val=pagetitle($page);
+ }
+
+ if (defined $val) {
+ if ($val=~/^$re$/i) {
+ return IkiWiki::SuccessReason->new("$re matches $field of $page");
+ }
+ else {
+ return IkiWiki::FailReason->new("$re does not match $field of $page");
+ }
+ }
+ else {
+ return IkiWiki::FailReason->new("$page does not have a $field");
+ }
+} #}}}
+
+package IkiWiki::PageSpec;
+
+sub match_title ($$;@) { #{{{
+ IkiWiki::Plugin::meta::match("title", @_);
+} #}}}
+
+sub match_author ($$;@) { #{{{
+ IkiWiki::Plugin::meta::match("author", @_);
+} #}}}
+
+sub match_authorurl ($$;@) { #{{{
+ IkiWiki::Plugin::meta::match("authorurl", @_);
+} #}}}
+
+sub match_license ($$;@) { #{{{
+ IkiWiki::Plugin::meta::match("license", @_);
+} #}}}
+
+sub match_copyright ($$;@) { #{{{
+ IkiWiki::Plugin::meta::match("copyright", @_);
+} #}}}
+
1
diff --git a/IkiWiki/Plugin/prettydate.pm b/IkiWiki/Plugin/prettydate.pm
index b6110e427..745e6a1de 100644
--- a/IkiWiki/Plugin/prettydate.pm
+++ b/IkiWiki/Plugin/prettydate.pm
@@ -63,6 +63,10 @@ sub checkconfig () { #{{{
sub IkiWiki::displaytime ($;$) { #{{{
my $time=shift;
+ my $format=shift;
+ if (! defined $format) {
+ $format=$config{prettydateformat};
+ }
eval q{use Date::Format};
error($@) if $@;
@@ -93,7 +97,6 @@ sub IkiWiki::displaytime ($;$) { #{{{
$t=~s{\%A-}{my @yest=@t; $yest[6]--; strftime("%A", \@yest)}eg;
- my $format=$config{prettydateformat};
$format=~s/\%X/$t/g;
return strftime($format, \@t);
} #}}}
diff --git a/IkiWiki/Plugin/recentchanges.pm b/IkiWiki/Plugin/recentchanges.pm
new file mode 100644
index 000000000..5ac0a30ef
--- /dev/null
+++ b/IkiWiki/Plugin/recentchanges.pm
@@ -0,0 +1,116 @@
+#!/usr/bin/perl
+package IkiWiki::Plugin::recentchanges;
+
+use warnings;
+use strict;
+use IkiWiki 2.00;
+
+sub import { #{{{
+ hook(type => "checkconfig", id => "recentchanges", call => \&checkconfig);
+ hook(type => "refresh", id => "recentchanges", call => \&refresh);
+ hook(type => "htmlize", id => "_change", call => \&htmlize);
+} #}}}
+
+sub checkconfig () { #{{{
+ $config{recentchangespage}='recentchanges' unless defined $config{recentchangespage};
+ $config{recentchangesnum}=100 unless defined $config{recentchangesnum};
+} #}}}
+
+sub refresh ($) { #{{{
+ my %seen;
+
+ # add new changes
+ foreach my $change (IkiWiki::rcs_recentchanges($config{recentchangesnum})) {
+ $seen{store($change, $config{recentchangespage})}=1;
+ }
+
+ # delete old and excess changes
+ foreach my $page (keys %pagesources) {
+ if ($page=~/^\Q$config{recentchangespage}\E\/change_/ && ! $seen{$page}) {
+ unlink($config{srcdir}.'/'.$pagesources{$page});
+ }
+ }
+} #}}}
+
+# Pages with extension _change have plain html markup, pass through.
+sub htmlize (@) { #{{{
+ my %params=@_;
+ return $params{content};
+} #}}}
+
+sub store ($$$) { #{{{
+ my $change=shift;
+
+ my $page="$config{recentchangespage}/change_".IkiWiki::titlepage($change->{rev});
+
+ # Optimisation to avoid re-writing pages. Assumes commits never
+ # change (or that any changes are not important).
+ return $page if exists $pagesources{$page} && ! $config{rebuild};
+
+ # Limit pages to first 10, and add links to the changed pages.
+ my $is_excess = exists $change->{pages}[10];
+ delete @{$change->{pages}}[10 .. @{$change->{pages}}] if $is_excess;
+ $change->{pages} = [
+ map {
+ if (length $config{url}) {
+ $_->{link} = "<a href=\"$config{url}/".
+ urlto($_->{page},"")."\">".
+ IkiWiki::pagetitle($_->{page})."</a>";
+ }
+ else {
+ $_->{link} = IkiWiki::pagetitle($_->{page});
+ }
+ $_->{baseurl}="$config{url}/" if length $config{url};
+
+ $_;
+ } @{$change->{pages}}
+ ];
+ push @{$change->{pages}}, { link => '...' } if $is_excess;
+
+ # See if the committer is an openid.
+ $change->{author}=$change->{user};
+ my $oiduser=IkiWiki::openiduser($change->{user});
+ if (defined $oiduser) {
+ $change->{authorurl}=$change->{user};
+ $change->{user}=$oiduser;
+ }
+ elsif (length $config{url}) {
+ $change->{authorurl}="$config{url}/".
+ (length $config{userdir} ? "$config{userdir}/" : "").
+ $change->{user};
+ }
+
+ # escape wikilinks and preprocessor stuff in commit messages
+ if (ref $change->{message}) {
+ foreach my $field (@{$change->{message}}) {
+ if (exists $field->{line}) {
+ $field->{line} =~ s/(?<!\\)\[\[/\\\[\[/g;
+ }
+ }
+ }
+
+ # Fill out a template with the change info.
+ my $template=template("change.tmpl", blind_cache => 1);
+ $template->param(
+ %$change,
+ commitdate => displaytime($change->{when}, "%X %x"),
+ wikiname => $config{wikiname},
+ );
+ IkiWiki::run_hooks(pagetemplate => sub {
+ shift->(page => $page, destpage => $page, template => $template);
+ });
+
+ my $file=$page."._change";
+ writefile($file, $config{srcdir}, $template->output);
+ utime $change->{when}, $change->{when}, "$config{srcdir}/$file";
+
+ return $page;
+} #}}}
+
+sub updatechanges ($$) { #{{{
+ my $subdir=shift;
+ my @changes=@{shift()};
+
+} #}}}
+
+1
diff --git a/IkiWiki/Plugin/version.pm b/IkiWiki/Plugin/version.pm
index d39fd9419..f96d2df06 100644
--- a/IkiWiki/Plugin/version.pm
+++ b/IkiWiki/Plugin/version.pm
@@ -18,7 +18,8 @@ sub needsbuild (@) { #{{{
if ($pagestate{$page}{version}{shown} ne $IkiWiki::version) {
push @$needsbuild, $pagesources{$page};
}
- if (grep { $_ eq $pagesources{$page} } @$needsbuild) {
+ if (exists $pagesources{$page} &&
+ grep { $_ eq $pagesources{$page} } @$needsbuild) {
# remove state, will be re-added if
# the version is still shown during the
# rebuild
diff --git a/IkiWiki/Rcs/Stub.pm b/IkiWiki/Rcs/Stub.pm
index 19ecfa88d..df347f6a9 100644
--- a/IkiWiki/Rcs/Stub.pm
+++ b/IkiWiki/Rcs/Stub.pm
@@ -37,6 +37,7 @@ sub rcs_recentchanges ($) {
# Examine the RCS history and generate a list of recent changes.
# The data structure returned for each change is:
# {
+ # rev => # the RCSs id for this commit
# user => # name of user who made the change,
# committype => # either "web" or the name of the rcs,
# when => # time when the change was made,
@@ -56,13 +57,6 @@ sub rcs_recentchanges ($) {
# }
}
-sub rcs_notify () {
- # This function is called when a change is committed to the wiki,
- # and ikiwiki is running as a post-commit hook from the RCS.
- # It should examine the repository to somehow determine what pages
- # changed, and then send emails to users subscribed to those pages.
-}
-
sub rcs_getctime ($) {
# Optional, used to get the page creation time from the RCS.
error gettext("getctime not implemented");
diff --git a/IkiWiki/Rcs/git.pm b/IkiWiki/Rcs/git.pm
index fea1c11eb..26a6f4266 100644
--- a/IkiWiki/Rcs/git.pm
+++ b/IkiWiki/Rcs/git.pm
@@ -247,8 +247,6 @@ sub _parse_diff_tree ($@) { #{{{
last;
}
- debug("No detail in diff-tree output") if !defined $ci{'details'};
-
return \%ci;
} #}}}
@@ -374,7 +372,7 @@ sub rcs_recentchanges ($) { #{{{
my ($sha1, $when) = (
$ci->{'sha1'},
- time - $ci->{'author_epoch'}
+ $ci->{'author_epoch'}
);
my (@pages, @messages);
@@ -421,50 +419,6 @@ sub rcs_recentchanges ($) { #{{{
return @rets;
} #}}}
-sub rcs_notify () { #{{{
- # Send notification mail to subscribed users.
- #
- # In usual Git usage, hooks/update script is presumed to send
- # notification mails (see git-receive-pack(1)). But we prefer
- # hooks/post-update to support IkiWiki commits coming from a
- # cloned repository (through command line) because post-update
- # is called _after_ each ref in repository is updated (update
- # hook is called _before_ the repository is updated). Since
- # post-update hook does not accept command line arguments, we
- # don't have an $ENV variable in this function.
- #
- # Here, we rely on a simple fact: we can extract all parts of the
- # notification content by parsing the "HEAD" commit (which also
- # triggers a refresh of IkiWiki pages).
-
- my $ci = git_commit_info('HEAD');
- return if !defined $ci;
-
- my @changed_pages = map { $_->{'file'} } @{ $ci->{'details'} };
-
- my ($user, $message);
- if (@{ $ci->{'comment'} }[0] =~ m/$config{web_commit_regexp}/) {
- $user = defined $2 ? "$2" : "$3";
- $message = $4;
- }
- else {
- $user = $ci->{'author_username'};
- $message = join "\n", @{ $ci->{'comment'} };
- }
-
- my $sha1 = $ci->{'sha1'};
-
- require IkiWiki::UserInfo;
- send_commit_mails(
- sub {
- $message;
- },
- sub {
- join "\n", run_or_die('git', 'diff', "${sha1}^", $sha1);
- }, $user, @changed_pages
- );
-} #}}}
-
sub rcs_getctime ($) { #{{{
my $file=shift;
# Remove srcdir prefix
diff --git a/IkiWiki/Rcs/mercurial.pm b/IkiWiki/Rcs/mercurial.pm
index 15edb3245..db6a396ac 100644
--- a/IkiWiki/Rcs/mercurial.pm
+++ b/IkiWiki/Rcs/mercurial.pm
@@ -142,7 +142,7 @@ sub rcs_recentchanges ($) { #{{{
rev => $info->{"changeset"},
user => $user,
committype => "mercurial",
- when => time - str2time($info->{"date"}),
+ when => str2time($info->{"date"}),
message => [@message],
pages => [@pages],
};
@@ -151,10 +151,6 @@ sub rcs_recentchanges ($) { #{{{
return @ret;
} #}}}
-sub rcs_notify () { #{{{
- # TODO
-} #}}}
-
sub rcs_getctime ($) { #{{{
my ($file) = @_;
diff --git a/IkiWiki/Rcs/monotone.pm b/IkiWiki/Rcs/monotone.pm
index 5717e0043..0ae2c1a32 100644
--- a/IkiWiki/Rcs/monotone.pm
+++ b/IkiWiki/Rcs/monotone.pm
@@ -416,7 +416,7 @@ sub rcs_recentchanges ($) { #{{{
$committype = "monotone";
}
} elsif ($cert->{name} eq "date") {
- $when = time - str2time($cert->{value}, 'UTC');
+ $when = str2time($cert->{value}, 'UTC');
} elsif ($cert->{name} eq "changelog") {
my $messageText = $cert->{value};
# split the changelog into multiple
@@ -452,54 +452,6 @@ sub rcs_recentchanges ($) { #{{{
return @ret;
} #}}}
-sub rcs_notify () { #{{{
- debug("The monotone rcs_notify function is currently untested. Use at own risk!");
-
- if (! exists $ENV{REV}) {
- error(gettext("REV is not set, not running from mtn post-commit hook, cannot send notifications"));
- }
- if ($ENV{REV} !~ m/($sha1_pattern)/) { # sha1 is untainted now
- error(gettext("REV is not a valid revision identifier, cannot send notifications"));
- }
- my $rev = $1;
-
- check_config();
-
- my $automator = Monotone->new();
- $automator->open(undef, $config{mtnrootdir});
-
- my $certs = [read_certs($automator, $rev)];
- my $user;
- my $message;
- my $when;
-
- foreach my $cert (@$certs) {
- if ($cert->{signature} eq "ok" && $cert->{trust} eq "trusted") {
- if ($cert->{name} eq "author") {
- $user = $cert->{value};
- } elsif ($cert->{name} eq "date") {
- $when = $cert->{value};
- } elsif ($cert->{name} eq "changelog") {
- $message = $cert->{value};
- }
- }
- }
-
- my @changed_pages = get_changed_files($automator, $rev);
-
- $automator->close();
-
- require IkiWiki::UserInfo;
- send_commit_mails(
- sub {
- return $message;
- },
- sub {
- `mtn --root=$config{mtnrootdir} au content_diff -r $rev`;
- },
- $user, @changed_pages);
-} #}}}
-
sub rcs_getctime ($) { #{{{
my $file=shift;
diff --git a/IkiWiki/Rcs/svn.pm b/IkiWiki/Rcs/svn.pm
index 987469ba0..f7d2242f0 100644
--- a/IkiWiki/Rcs/svn.pm
+++ b/IkiWiki/Rcs/svn.pm
@@ -171,7 +171,7 @@ sub rcs_recentchanges ($) { #{{{
my $rev = $logentry->{revision};
my $user = $logentry->{author};
- my $when=time - str2time($logentry->{date}, 'UTC');
+ my $when=str2time($logentry->{date}, 'UTC');
foreach my $msgline (split(/\n/, $logentry->{msg})) {
push @message, { line => $msgline };
@@ -203,7 +203,8 @@ sub rcs_recentchanges ($) { #{{{
diffurl => $diffurl,
} if length $file;
}
- push @ret, { rev => $rev,
+ push @ret, {
+ rev => $rev,
user => $user,
committype => $committype,
when => $when,
@@ -216,44 +217,6 @@ sub rcs_recentchanges ($) { #{{{
return @ret;
} #}}}
-sub rcs_notify () { #{{{
- if (! exists $ENV{REV}) {
- error(gettext("REV is not set, not running from svn post-commit hook, cannot send notifications"));
- }
- my $rev=int(possibly_foolish_untaint($ENV{REV}));
-
- my $user=`svnlook author $config{svnrepo} -r $rev`;
- chomp $user;
-
- my $message=`svnlook log $config{svnrepo} -r $rev`;
- if ($message=~/$config{web_commit_regexp}/) {
- $user=defined $2 ? "$2" : "$3";
- $message=$4;
- }
-
- my @changed_pages;
- foreach my $change (`svnlook changed $config{svnrepo} -r $rev`) {
- chomp $change;
- if (length $config{svnpath}) {
- if ($change =~ /^[A-Z]+\s+\Q$config{svnpath}\E\/(.*)/) {
- push @changed_pages, $1;
- }
- }
- else {
- push @changed_pages, $change;
- }
- }
-
- require IkiWiki::UserInfo;
- send_commit_mails(
- sub {
- return $message;
- },
- sub {
- `svnlook diff $config{svnrepo} -r $rev --no-diff-deleted`;
- }, $user, @changed_pages);
-} #}}}
-
sub rcs_getctime ($) { #{{{
my $file=shift;
diff --git a/IkiWiki/Rcs/tla.pm b/IkiWiki/Rcs/tla.pm
index 1dbc006c1..ecc561bde 100644
--- a/IkiWiki/Rcs/tla.pm
+++ b/IkiWiki/Rcs/tla.pm
@@ -120,7 +120,7 @@ sub rcs_recentchanges ($) {
split(/ /, "$newfiles $modfiles .arch-ids/fake.id");
my $sdate = $head->get("Standard-date");
- my $when = time - str2time($sdate, 'UTC');
+ my $when = str2time($sdate, 'UTC');
my $committype = "web";
if (defined $summ && $summ =~ /$config{web_commit_regexp}/) {
@@ -145,7 +145,8 @@ sub rcs_recentchanges ($) {
diffurl => $diffurl,
} if length $file;
}
- push @ret, { rev => $change,
+ push @ret, {
+ rev => $change,
user => $user,
committype => $committype,
when => $when,
@@ -159,51 +160,6 @@ sub rcs_recentchanges ($) {
return @ret;
}
-sub rcs_notify () { #{{{
- # FIXME: Not set
- if (! exists $ENV{ARCH_VERSION}) {
- error("ARCH_VERSION is not set, not running from tla post-commit hook, cannot send notifications");
- }
- my $rev=int(possibly_foolish_untaint($ENV{REV}));
-
- eval q{use Mail::Header};
- error($@) if $@;
- open(LOG, $ENV{"ARCH_LOG"});
- my $head = Mail::Header->new(\*LOG);
- close(LOG);
-
- my $user = $head->get("Creator");
-
- my $newfiles = $head->get("New-files");
- my $modfiles = $head->get("Modified-files");
- my $remfiles = $head->get("Removed-files");
-
- my @changed_pages = grep { !/(^.*\/)?\.arch-ids\/.*\.id$/ }
- split(/ /, "$newfiles $modfiles $remfiles .arch-ids/fake.id");
-
- require IkiWiki::UserInfo;
- send_commit_mails(
- sub {
- my $message = $head->get("Summary");
- if ($message =~ /$config{web_commit_regexp}/) {
- $user=defined $2 ? "$2" : "$3";
- $message=$4;
- }
- },
- sub {
- my $logs = `tla logs -d $config{srcdir}`;
- my @changesets = reverse split(/\n/, $logs);
- my $i;
-
- for($i=0;$i<$#changesets;$i++) {
- last if $changesets[$i] eq $rev;
- }
-
- my $revminusone = $changesets[$i+1];
- `tla diff -d $ENV{ARCH_TREE_ROOT} $revminusone`;
- }, $user, @changed_pages);
-} #}}}
-
sub rcs_getctime ($) { #{{{
my $file=shift;
eval q{use Date::Parse};
diff --git a/IkiWiki/Render.pm b/IkiWiki/Render.pm
index 4fefadf09..be5af84ba 100644
--- a/IkiWiki/Render.pm
+++ b/IkiWiki/Render.pm
@@ -82,9 +82,12 @@ sub genpage ($$) { #{{{
if (length $config{cgiurl}) {
$template->param(editurl => cgiurl(do => "edit", page => pagetitle($page, 1)));
$template->param(prefsurl => cgiurl(do => "prefs"));
- if ($config{rcs}) {
- $template->param(recentchangesurl => cgiurl(do => "recentchanges"));
- }
+ $actions++;
+ }
+
+ if ($config{rcs} && exists $config{recentchangespage} &&
+ $page ne $config{recentchangespage}) {
+ $template->param(recentchangesurl => urlto($config{recentchangespage}, $page));
$actions++;
}
@@ -196,6 +199,7 @@ sub render ($) { #{{{
my $page=pagename($file);
delete $depends{$page};
will_render($page, htmlpage($page), 1);
+ return if $type=~/^_/;
my $content=htmlize($page, $type,
linkify($page, $page,
@@ -256,6 +260,8 @@ sub refresh () { #{{{
$test=dirname($test);
}
}
+
+ run_hooks(refresh => sub { shift->() });
# find existing pages
my %exists;
@@ -314,15 +320,19 @@ sub refresh () { #{{{
}, $dir);
};
- my %rendered;
+ my (%rendered, @add, @del, @internal);
# check for added or removed pages
- my @add;
foreach my $file (@files) {
my $page=pagename($file);
$pagesources{$page}=$file;
if (! $pagemtime{$page}) {
- push @add, $file;
+ if (isinternal($page)) {
+ push @internal, $file;
+ }
+ else {
+ push @add, $file;
+ }
$pagecase{lc $page}=$page;
if ($config{getctime} && -e "$config{srcdir}/$file") {
$pagectime{$page}=rcs_getctime("$config{srcdir}/$file");
@@ -332,11 +342,15 @@ sub refresh () { #{{{
}
}
}
- my @del;
foreach my $page (keys %pagemtime) {
if (! $exists{$page}) {
- debug(sprintf(gettext("removing old page %s"), $page));
- push @del, $pagesources{$page};
+ if (isinternal($page)) {
+ push @internal, $pagesources{$page};
+ }
+ else {
+ debug(sprintf(gettext("removing old page %s"), $page));
+ push @del, $pagesources{$page};
+ }
$links{$page}=[];
$renderedfiles{$page}=[];
$pagemtime{$page}=0;
@@ -361,7 +375,14 @@ sub refresh () { #{{{
$mtime > $pagemtime{$page} ||
$forcerebuild{$page}) {
$pagemtime{$page}=$mtime;
- push @needsbuild, $file;
+ if (isinternal($page)) {
+ push @internal, $file;
+ # Preprocess internal page in scan-only mode.
+ preprocess($page, $page, readfile(srcfile($file)), 1);
+ }
+ else {
+ push @needsbuild, $file;
+ }
}
}
run_hooks(needsbuild => sub { shift->(\@needsbuild) });
@@ -377,6 +398,15 @@ sub refresh () { #{{{
render($file);
$rendered{$file}=1;
}
+ foreach my $file (@internal) {
+ # internal pages are not rendered
+ my $page=pagename($file);
+ delete $depends{$page};
+ foreach my $old (@{$renderedfiles{$page}}) {
+ delete $destsources{$old};
+ }
+ $renderedfiles{$page}=[];
+ }
# rebuild pages that link to added or removed pages
if (@add || @del) {
@@ -392,13 +422,17 @@ sub refresh () { #{{{
}
}
- if (%rendered || @del) {
+ if (%rendered || @del || @internal) {
+ my @changed=(keys %rendered, @del);
+
# rebuild dependant pages
foreach my $f (@files) {
next if $rendered{$f};
my $p=pagename($f);
if (exists $depends{$p}) {
- foreach my $file (keys %rendered, @del) {
+ # only consider internal files
+ # if the page explicitly depends on such files
+ foreach my $file (@changed, $depends{$p}=~/internal\(/ ? @internal : ()) {
next if $f eq $file;
my $page=pagename($file);
if (pagespec_match($page, $depends{$p}, location => $p)) {
@@ -414,7 +448,7 @@ sub refresh () { #{{{
# handle backlinks; if a page has added/removed links,
# update the pages it links to
my %linkchanged;
- foreach my $file (keys %rendered, @del) {
+ foreach my $file (@changed) {
my $page=pagename($file);
if (exists $links{$page}) {
@@ -436,6 +470,7 @@ sub refresh () { #{{{
}
}
}
+
foreach my $link (keys %linkchanged) {
my $linkfile=$pagesources{$link};
if (defined $linkfile) {
diff --git a/IkiWiki/UserInfo.pm b/IkiWiki/UserInfo.pm
index cfc27609d..2ffc51c55 100644
--- a/IkiWiki/UserInfo.pm
+++ b/IkiWiki/UserInfo.pm
@@ -92,91 +92,4 @@ sub set_banned_users (@) { #{{{
return userinfo_store($userinfo);
} #}}}
-sub commit_notify_list ($@) { #{{{
- my $committer=shift;
- my @pages = map pagename($_), @_;
-
- my @ret;
- my $userinfo=userinfo_retrieve();
- foreach my $user (keys %{$userinfo}) {
- next if $user eq $committer;
- if (exists $userinfo->{$user}->{subscriptions} &&
- length $userinfo->{$user}->{subscriptions} &&
- exists $userinfo->{$user}->{email} &&
- length $userinfo->{$user}->{email} &&
- grep { pagespec_match($_,
- $userinfo->{$user}->{subscriptions},
- user => $committer) }
- map pagename($_), @_) {
- push @ret, $userinfo->{$user}->{email};
- }
- }
- return @ret;
-} #}}}
-
-sub send_commit_mails ($$$@) { #{{{
- my $messagesub=shift;
- my $diffsub=shift;
- my $user=shift;
- my @changed_pages=@_;
-
- return unless @changed_pages;
-
- my @email_recipients=commit_notify_list($user, @changed_pages);
- if (@email_recipients) {
- # TODO: if a commit spans multiple pages, this will send
- # subscribers a diff that might contain pages they did not
- # sign up for. Should separate the diff per page and
- # reassemble into one mail with just the pages subscribed to.
- my $diff=$diffsub->();
- my $message=$messagesub->();
-
- my $pagelist;
- if (@changed_pages > 2) {
- $pagelist="$changed_pages[0] $changed_pages[1] ...";
- }
- else {
- $pagelist.=join(" ", @changed_pages);
- }
- #translators: The three variables are the name of the wiki,
- #translators: A list of one or more pages that were changed,
- #translators: And the name of the user making the change.
- #translators: This is used as the subject of a commit email.
- my $subject=sprintf(gettext("update of %s's %s by %s"),
- $config{wikiname}, $pagelist, $user);
-
- my $template=template("notifymail.tmpl");
- $template->param(
- wikiname => $config{wikiname},
- diff => $diff,
- user => $user,
- message => $message,
- );
-
- # Daemonize, in case the mail sending takes a while.
- defined(my $pid = fork) or error("Can't fork: $!");
- return if $pid;
- setsid() or error("Can't start a new session: $!");
- chdir '/';
- open STDIN, '/dev/null';
- open STDOUT, '>/dev/null';
- open STDERR, '>&STDOUT' or error("Can't dup stdout: $!");
-
- unlockwiki(); # don't need to keep a lock on the wiki
-
- eval q{use Mail::Sendmail};
- error($@) if $@;
- foreach my $email (@email_recipients) {
- sendmail(
- To => $email,
- From => "$config{wikiname} <$config{adminemail}>",
- Subject => $subject,
- Message => $template->output,
- );
- }
-
- exit 0; # daemon process done
- }
-} #}}}
-
1
diff --git a/IkiWiki/Wrapper.pm b/IkiWiki/Wrapper.pm
index 2103ea53a..90a4c46c7 100644
--- a/IkiWiki/Wrapper.pm
+++ b/IkiWiki/Wrapper.pm
@@ -36,22 +36,6 @@ sub gen_wrapper () { #{{{
addenv("$var", s);
EOF
}
- if ($config{rcs} eq "svn" && $config{notify}) {
- # Support running directly as hooks/post-commit by passing
- # $2 in REV in the environment.
- $envsave.=<<"EOF"
- if (argc == 3)
- addenv("REV", argv[2]);
- else if ((s=getenv("REV")))
- addenv("REV", s);
-EOF
- }
- if ($config{rcs} eq "tla" && $config{notify}) {
- $envsave.=<<"EOF"
- if ((s=getenv("ARCH_VERSION")))
- addenv("ARCH_VERSION", s);
-EOF
- }
$Data::Dumper::Indent=0; # no newlines
my $configstring=Data::Dumper->Dump([\%config], ['*config']);