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 add_link
%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
- our $installdir=''; # INSTALLDIR_AUTOREPLACE done by Makefile, DNE
+ our $installdir='/usr'; # INSTALLDIR_AUTOREPLACE done by Makefile, DNE
# Optimisation.
use Memoize;
safe => 0, # path
rebuild => 0,
},
+ underlaydirbase => {
+ type => "internal",
+ default => "$installdir/share/ikiwiki",
+ description => "parent directory containing additional underlays",
+ safe => 0,
+ rebuild => 0,
+ },
wrappers => {
type => "internal",
default => [],
my $dir=shift;
if ($dir !~ /^\//) {
- $dir="$config{underlaydir}/../$dir";
+ $dir="$config{underlaydirbase}/$dir";
}
if (! grep { $_ eq $dir } @{$config{underlaydirs}}) {
foreach my $line (split("\n", $params{content})) {
push @diff, $line if ! exists $old{$_};
}
- $params{content}=join("\n", @diff);
+ $params{diff}=join("\n", @diff);
}
my $ok;
$hooks{rcs}{rcs_receive}{call}->();
}
- sub safequote ($) {
- my $s=shift;
- $s=~s/[{}]//g;
- return "q{$s}";
- }
-
sub add_depends ($$) {
my $page=shift;
my $pagespec=shift;
use warnings;
}
+ sub add_link ($$) {
+ my $page=shift;
+ my $link=shift;
+
+ push @{$links{$page}}, $link
+ unless grep { $_ eq $link } @{$links{$page}};
+ }
+
sub pagespec_merge ($$) {
my $a=shift;
my $b=shift;
# Convert spec to perl code.
my $code="";
+ my @data;
while ($spec=~m{
\s* # ignore whitespace
( # 1: match a single word
}
elsif ($word =~ /^(\w+)\((.*)\)$/) {
if (exists $IkiWiki::PageSpec::{"match_$1"}) {
- $code.="IkiWiki::PageSpec::match_$1(\$page, ".safequote($2).", \@_)";
+ push @data, $2;
+ $code.="IkiWiki::PageSpec::match_$1(\$page, \$data[$#data], \@_)";
}
else {
- $code.="IkiWiki::FailReason->new(".safequote(qq{unknown function in pagespec "$word"}).")";
+ push @data, qq{unknown function in pagespec "$word"};
+ $code.="IkiWiki::ErrorReason->new(\$data[$#data])";
}
}
else {
- $code.=" IkiWiki::PageSpec::match_glob(\$page, ".safequote($word).", \@_)";
+ push @data, $word;
+ $code.=" IkiWiki::PageSpec::match_glob(\$page, \$data[$#data], \@_)";
}
}
}
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;
return bless \$value, $class;
}
+ package IkiWiki::ErrorReason;
+
+ our @ISA = 'IkiWiki::FailReason';
+
package IkiWiki::SuccessReason;
use overload (
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) {
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})) {
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) {
sub import {
hook(type => "getsetup", id => "blogspam", call => \&getsetup);
+ hook(type => "checkconfig", id => "blogspam", call => \&checkconfig);
hook(type => "checkcontent", id => "blogspam", call => \&checkcontent);
}
},
}
- sub checkcontent (@) {
- my %params=@_;
-
+ sub checkconfig () {
+ # This is done at checkconfig time because printing an error
+ # if the module is missing when a spam is posted would not
+ # let the admin know about the problem.
eval q{
use RPC::XML;
use RPC::XML::Client;
};
- if ($@) {
- warn($@);
- return undef;
- }
+ error $@ if $@;
+ }
+
+ sub checkcontent (@) {
+ my %params=@_;
if (exists $config{blogspam_pagespec}) {
return undef
my %req=(
ip => $ENV{REMOTE_ADDR},
- comment => $params{content},
+ comment => defined $params{diff} ? $params{diff} : $params{content},
subject => defined $params{subject} ? $params{subject} : "",
name => defined $params{author} ? $params{author} : "",
link => exists $params{url} ? $params{url} : "",
- ikiwiki (3.11) unstable; urgency=low
++ikiwiki (3.14) UNRELEASED; urgency=low
+
+ * Add new hooks: canremove, canrename, rename. (intrigeri)
+ * rename: Refactor subpage rename handling code into rename hook. (intrigeri)
+ * po: New plugin, suporting translation of wiki pages using po files.
+ (intrigeri)
+
+ -- Joey Hess <joeyh@debian.org> Mon, 20 Apr 2009 19:40:25 -0400
+
+ ikiwiki (3.13) UNRELEASED; urgency=low
+
+ * ikiwiki-transition: If passed a nonexistant srcdir, or one not
+ containing .ikiwiki, abort with an error rather than creating it.
+ * Allow underlaydir to be overridden without messing up inclusion
+ of other underlays via add_underlay.
+ * More friendly display of markdown, textile in edit form selector
+ (jmtd)
+ * Allow curly braces to be used in pagespecs, and avoid a whole class
+ of potential security problems, by avoiding performing any string
+ interpolation on user-supplied data when translating pagespecs.
+
+ -- Joey Hess <joeyh@debian.org> Wed, 06 May 2009 20:45:44 -0400
+
+ ikiwiki (3.12) unstable; urgency=low
+
+ * Re-enable python-support and add python:Depends to control file.
+ * ikiwiki-makerepo: Avoid using abs_path, as it apparently
+ fails on nonexistant directories with some broken perl
+ versions.
+ * inline: Minor optimisation.
+ * add_link: New function, which plugins should use rather than
+ modifying %links directly, to avoid it accumulating duplicates.
+ * ikiwiki-transition: Add a deduplinks action, that can be used
+ to remove duplicate links and optimise a wiki w/o rebuilding it.
+ * external: Fix pagespec_match and pagespec_match_list.
+ Closes: #527281
+
+ -- Joey Hess <joeyh@debian.org> Wed, 06 May 2009 00:31:16 -0400
+
+ ikiwiki (3.11) unstable; urgency=low
+
+ * Avoid using python-support. Closes: #525086
+ * websetup: Display stderr in browser if ikiwiki setup fails.
+ * blogspam: Load RPC::XML library in checkconfig, so that an
+ error can be printed at that point if it's not available,
+ allowing the admin to see it during wiki setup.
+ Closes: #520015
+ * websetup: If setup fails, restore old setup file.
+ * relativedate: Deal with clock skew.
+ * Add IkiWiki::ErrorReason objects, and modify pagespecs to return
+ them in cases where they fail to match due to a configuration or syntax
+ error.
+ * pagespec_match_list: New API function, matches pages in a list
+ and throws an error if the pagespec is bad.
+ * inline, brokenlinks, calendar, linkmap, map, orphans, pagecount,
+ pagestate, postsparkline: Display a handy error message if the pagespec
+ is erronious.
+ * comments: Add link to comment post form to allow user to sign in
+ if they wish to, if the configuration makes signin optional
+ for commenting.
+ * Updated Danish translation from Jonas Smedegaard. Closes: #525751
+ * translation.mdwn: Typo fixes. Closes: #525753
+
+ -- Joey Hess <joeyh@debian.org> Mon, 04 May 2009 15:45:10 -0400
+
ikiwiki (3.10) unstable; urgency=low
* darcs: Finally added support for this VCS, thanks to many
libhtml-parser-perl, liburi-perl, perlmagick
Maintainer: Joey Hess <joeyh@debian.org>
Uploaders: Josh Triplett <josh@freedesktop.org>
- Standards-Version: 3.8.0
+ Standards-Version: 3.8.1
Homepage: http://ikiwiki.info/
Vcs-Git: git://git.ikiwiki.info/
Vcs-Browser: http://git.ikiwiki.info/?p=ikiwiki
Package: ikiwiki
Architecture: all
- Depends: ${misc:Depends}, ${perl:Depends},
+ Depends: ${misc:Depends}, ${perl:Depends}, ${python:Depends},
libtext-markdown-perl | markdown,
libhtml-scrubber-perl, libhtml-template-perl,
libhtml-parser-perl, liburi-perl
liblocale-gettext-perl (>= 1.05-1), libtext-typography-perl,
libtext-csv-perl, libdigest-sha1-perl, graphviz, libnet-amazon-s3-perl,
sparkline-php, texlive, dvipng, libtext-wikicreole-perl,
- libsort-naturally-perl, libtext-textile-perl
+ libsort-naturally-perl, libtext-textile-perl, po4a (>= 0.35-1), gettext
Conflicts: ikiwiki-plugin-table
Replaces: ikiwiki-plugin-table
Provides: ikiwiki-plugin-table
This allows a plugin to manipulate the list of files that need to be
built when the wiki is refreshed. The function is passed a reference to an
- array of pages that will be rebuilt, and can modify the array, either
+ array of files that will be rebuilt, and can modify the array, either
adding or removing files from it.
### scan
This hook is called early in the process of building the wiki, and is used
as a first pass scan of the page, to collect metadata about the page. It's
- mostly used to scan the page for [[WikiLinks|ikiwiki/WikiLink]], and add them to `%links`.
- Present in IkiWiki 2.40 and later.
+ mostly used to scan the page for [[WikiLinks|ikiwiki/WikiLink]], and add
+ them to `%links`. Present in IkiWiki 2.40 and later.
The function is passed named parameters "page" and "content". Its return
value is ignored.
If `hook` is passed an optional "scan" parameter, set to a true value, this
makes the hook be called during the preliminary scan that ikiwiki makes of
updated pages, before begining to render pages. This should be done if the
- hook modifies data in `%links`. Note that doing so will make the hook be
- run twice per page build, so avoid doing it for expensive hooks. (As an
- optimisation, if your preprocessor hook is called in a void context, you
- can assume it's being run in scan mode, and avoid doing expensive things at
- that point.)
+ hook modifies data in `%links` (typically by calling `add_link`). Note that
+ doing so will make the hook be run twice per page build, so avoid doing it
+ for expensive hooks. (As an optimisation, if your preprocessor hook is
+ called in a void context, you can assume it's being run in scan mode, and
+ avoid doing expensive things at that point.)
Note that if the [[htmlscrubber]] is enabled, html in
preprocessor [[ikiwiki/directive]] output is sanitised, which may limit what
and later.
Plugins that implement linkify must also implement a scan hook, that scans
- for the links on the page and adds them to `%links`.
+ for the links on the page and adds them to `%links` (typically by calling
+ `add_link`).
### htmlize
a whole filename that can be htmlized. This is useful for files
like `Makefile` that have no extension.
+ If `hook` is passed an optional "longname" parameter, this value is used
+ when prompting a user to choose a page type on the edit page form.
+
### pagetemplate
hook(type => "pagetemplate", id => "foo", call => \&pagetemplate);
since it's sometimes used to test to see which pages in a set of pages a
user can edit.
+### canremove
+
+ hook(type => "canremove", id => "foo", call => \&canremove);
+
+This hook can be used to implement arbitrary access methods to control
+when a page can be removed using the web interface (commits from
+revision control bypass it). It works exactly like the `canedit` hook,
+but is passed the named parameters `cgi` (a CGI object), `session`
+(a session object) and `page` (the page subject to deletion).
+
+### canrename
+
+ hook(type => "canrename", id => "foo", call => \&canrename);
+
+This hook can be used to implement arbitrary access methods to control when
+a page can be renamed using the web interface (commits from revision control
+bypass it). It works exactly like the `canedit` hook,
+but is passed the named parameters `cgi` (a CGI object), `session` (a
+session object), `src`, `srcfile`, `dest` and `destfile`.
+
### checkcontent
hook(type => "checkcontent", id => "foo", call => \&checkcontent);
additional parameters: `author`, `url`, and `subject`. The `subject`
parameter may also be filled with the user's comment about the change.
-Note: When the user edits an existing wiki page, the passed `content` will
-include only the lines that they added to the page, or modified.
+Note: When the user edits an existing wiki page, this hook is also
+passed a `diff` named parameter, which will include only the lines
+that they added to the page, or modified.
The hook should return `undef` on success. If the content is disallowed, it
should return a message stating what the problem is, or a function
hook(type => "renamepage", id => "foo", call => \&renamepage);
This hook is called by the [[plugins/rename]] plugin when it renames
-something. The hook is passed named parameters: `page`, `oldpage`,
-`newpage`, and `content`, and should try to modify the content to reflect
-the name change. For example, by converting links to point to the new page.
+something, once per page linking to the renamed page's old location.
+The hook is passed named parameters: `page`, `oldpage`, `newpage`, and
+`content`, and should try to modify the content of `page` to reflect
+the name change. For example, by converting links to point to the
+new page.
+
+### rename
+
+ hook(type => "rename", id => "foo", call => \&rename);
+
+When a page or set of pages is renamed, the referenced function is
+called for every page, and is passed named parameters:
+
+* `torename`: a reference to a hash with keys: `src`, `srcfile`,
+ `dest`, `destfile`, `required`.
+* `cgi`: a CGI object
+* `session`: a session object.
+
+Such a hook function returns any additional rename hashes it wants to
+add. This hook is applied recursively to returned additional rename
+hashes, so that it handles the case where two plugins use the hook:
+plugin A would see when plugin B adds a new file to be renamed.
### getsetup
PageSpec should match against. If not passed, relative PageSpecs will match
relative to the top of the wiki.
+ #### `pagespec_match_list($$;@)`
+
+ Passed a reference to a list of page names, and [[ikiwiki/PageSpec]],
+ returns the set of pages that match the [[ikiwiki/PageSpec]].
+
+ Additional named parameters can be passed, to further limit the match.
+ The most often used is "location", which specifies the location the
+ PageSpec should match against. If not passed, relative PageSpecs will match
+ relative to the top of the wiki.
+
+ Unlike pagespec_match, this may throw an error if there is an error in
+ the pagespec.
+
#### `bestlink($$)`
Given a page and the text of a link on the page, determine which
filename of the page. For example, `targetpage("foo", "rss", "feed")`
will yield something like `foo/feed.rss`.
+ #### `add_link($$)`
+
+ This adds a link to `%links`, ensuring that duplicate links are not
+ added. Pass it the page that contains the link, and the link text.
+
## Miscellaneous
### Internal use pages
IkiWiki::PageSpec package, that is named `match_foo`, where "foo()" is
how it will be accessed in a [[ikiwiki/PageSpec]]. The function will be passed
two parameters: The name of the page being matched, and the thing to match
- against. It may also be passed additional, named parameters. It should return
- a IkiWiki::SuccessReason object if the match succeeds, or an
- IkiWiki::FailReason object if the match fails.
+ against. It may also be passed additional, named parameters.
+
+ It should return a IkiWiki::SuccessReason object if the match succeeds, or
+ an IkiWiki::FailReason object if the match fails. If the match cannot be
+ attempted at all, for any page, it can instead return an
+ IkiWiki::ErrorReason object explaining why.
### Setup plugins