add use_pagespec and deptype functions
parent
c57908b9d0
commit
5e236f5d25
141
IkiWiki.pm
141
IkiWiki.pm
|
@ -17,11 +17,12 @@ use vars qw{%config %links %oldlinks %pagemtime %pagectime %pagecase
|
|||
%forcerebuild %loaded_plugins};
|
||||
|
||||
use Exporter q{import};
|
||||
our @EXPORT = qw(hook debug error template htmlpage add_depends pagespec_match
|
||||
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
|
||||
our @EXPORT = qw(hook debug error template htmlpage deptype use_pagespec
|
||||
add_depends pagespec_match 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
|
||||
|
@ -1768,18 +1769,10 @@ sub rcs_receive () {
|
|||
$hooks{rcs}{rcs_receive}{call}->();
|
||||
}
|
||||
|
||||
sub add_depends ($$;@) {
|
||||
sub add_depends ($$;$) {
|
||||
my $page=shift;
|
||||
my $pagespec=shift;
|
||||
|
||||
my $deptype=0;
|
||||
if (@_) {
|
||||
my %params=@_;
|
||||
|
||||
$deptype=$deptype | $DEPEND_PRESENCE if $params{presence};
|
||||
$deptype=$deptype | $DEPEND_LINKS if $params{links};
|
||||
}
|
||||
$deptype=$DEPEND_CONTENT unless $deptype;
|
||||
my $deptype=shift || $DEPEND_CONTENT;
|
||||
|
||||
# Is the pagespec a simple page name?
|
||||
if ($pagespec =~ /$config{wiki_file_regexp}/ &&
|
||||
|
@ -1791,20 +1784,120 @@ sub add_depends ($$;@) {
|
|||
# Analyse the pagespec, and match it against all pages
|
||||
# to get a list of influences, and add explicit dependencies
|
||||
# for those.
|
||||
my $sub=pagespec_translate($pagespec);
|
||||
return if $@;
|
||||
foreach my $p (keys %pagesources) {
|
||||
my $r=$sub->($p, location => $page );
|
||||
my %i=$r->influences;
|
||||
foreach my $i (keys %i) {
|
||||
$depends_simple{$page}{lc $i} |= $i{$i};
|
||||
}
|
||||
}
|
||||
#my $sub=pagespec_translate($pagespec);
|
||||
#return if $@;
|
||||
#foreach my $p (keys %pagesources) {
|
||||
# my $r=$sub->($p, location => $page );
|
||||
# my %i=$r->influences;
|
||||
# foreach my $i (keys %i) {
|
||||
# $depends_simple{$page}{lc $i} |= $i{$i};
|
||||
# }
|
||||
#}
|
||||
print STDERR "warning: use of add_depends; influences not tracked\n";
|
||||
|
||||
$depends{$page}{$pagespec} |= $deptype;
|
||||
return 1;
|
||||
}
|
||||
|
||||
sub use_pagespec ($$;@) {
|
||||
my $page=shift;
|
||||
my $pagespec=shift;
|
||||
my %params=@_;
|
||||
|
||||
my $sub=pagespec_translate($pagespec);
|
||||
error "syntax error in pagespec \"$pagespec\""
|
||||
if $@ || ! defined $sub;
|
||||
|
||||
my @candidates;
|
||||
if (exists $params{limit}) {
|
||||
@candidates=grep { $params{limit}->($_) } keys %pagesources;
|
||||
}
|
||||
else {
|
||||
@candidates=keys %pagesources;
|
||||
}
|
||||
|
||||
if (defined $params{sort}) {
|
||||
my $f;
|
||||
if ($params{sort} eq 'title') {
|
||||
$f=sub { pagetitle(basename($a)) cmp pagetitle(basename($b)) };
|
||||
}
|
||||
elsif ($params{sort} eq 'title_natural') {
|
||||
eval q{use Sort::Naturally};
|
||||
if ($@) {
|
||||
error(gettext("Sort::Naturally needed for title_natural sort"));
|
||||
}
|
||||
$f=sub { Sort::Naturally::ncmp(pagetitle(basename($a)), pagetitle(basename($b))) };
|
||||
}
|
||||
elsif ($params{sort} eq 'mtime') {
|
||||
$f=sub { $pagemtime{$b} <=> $pagemtime{$a} };
|
||||
}
|
||||
elsif ($params{sort} eq 'age') {
|
||||
$f=sub { $pagectime{$b} <=> $pagectime{$a} };
|
||||
}
|
||||
else {
|
||||
error sprintf(gettext("unknown sort type %s"), $params{sort});
|
||||
}
|
||||
@candidates = sort { &$f } @candidates;
|
||||
}
|
||||
|
||||
@candidates=reverse(@candidates) if $params{reverse};
|
||||
|
||||
my @matches;
|
||||
my $firstfail;
|
||||
my $count=0;
|
||||
foreach my $p (@candidates) {
|
||||
my $r=$sub->($p, location => $page);
|
||||
if ($r) {
|
||||
push @matches, [$p, $r];
|
||||
last if defined $params{num} && ++$count == $params{num};
|
||||
}
|
||||
elsif (! defined $firstfail) {
|
||||
$firstfail=$r;
|
||||
}
|
||||
}
|
||||
|
||||
$depends{$page}{$pagespec} |= ($params{deptype} || $DEPEND_CONTENT);
|
||||
|
||||
my @ret;
|
||||
if (@matches) {
|
||||
# Add all influences from successful matches.
|
||||
foreach my $m (@matches) {
|
||||
push @ret, $m->[0];
|
||||
my %i=$m->[1]->influences;
|
||||
foreach my $i (keys %i) {
|
||||
$depends_simple{$page}{lc $i} |= $i{$i};
|
||||
}
|
||||
}
|
||||
}
|
||||
elsif (defined $firstfail) {
|
||||
# Add influences from one failure. (Which one should not
|
||||
# matter; all should have the same influences.)
|
||||
my %i=$firstfail->influences;
|
||||
foreach my $i (keys %i) {
|
||||
$depends_simple{$page}{lc $i} |= $i{$i};
|
||||
}
|
||||
error(sprintf(gettext("cannot match pages: %s"), $firstfail));
|
||||
}
|
||||
|
||||
return @ret;
|
||||
}
|
||||
|
||||
sub deptype (@) {
|
||||
my $deptype=0;
|
||||
foreach my $type (@_) {
|
||||
if ($type eq 'presence') {
|
||||
$deptype |= $DEPEND_PRESENCE;
|
||||
}
|
||||
elsif ($type eq 'links') {
|
||||
$deptype |= $DEPEND_LINKS;
|
||||
}
|
||||
elsif ($type eq 'content') {
|
||||
$deptype |= $DEPEND_CONTENT;
|
||||
}
|
||||
}
|
||||
return $deptype;
|
||||
}
|
||||
|
||||
sub file_pruned ($$) {
|
||||
require File::Spec;
|
||||
my $file=File::Spec->canonpath(shift);
|
||||
|
|
|
@ -13,7 +13,6 @@ ikiwiki (3.14159266) UNRELEASED; urgency=low
|
|||
* Added support framework for multiple types of dependencies.
|
||||
* Allow declaring that a dependency is only affected by page presence
|
||||
or changes to its links.
|
||||
(By passing presence => 1 or links => 1 to add_depends.)
|
||||
* pagecount, calendar, postsparkline, progress: Use a presence dependency,
|
||||
which makes these directives much less expensive to use, since page
|
||||
edits will no longer trigger an unnecessary update.
|
||||
|
@ -34,6 +33,9 @@ ikiwiki (3.14159266) UNRELEASED; urgency=low
|
|||
info.
|
||||
* Plugins providing PageSpec `match_*` functions should pass additional
|
||||
influence information when creating result objects.
|
||||
* Added `use_pagespec` function, that plugins can use to find a list
|
||||
of matching pages and add dependencies and influences, all at once,
|
||||
and efficiently.
|
||||
|
||||
-- Joey Hess <joeyh@debian.org> Sun, 27 Sep 2009 17:40:03 -0400
|
||||
|
||||
|
|
|
@ -609,21 +609,52 @@ page created from it. (Ie, it appends ".html".)
|
|||
Use this when constructing the filename of a html file. Use `urlto` when
|
||||
generating a link to a page.
|
||||
|
||||
#### `add_depends($$;@)`
|
||||
### `deptype(@)`
|
||||
|
||||
Use this function to generate ikiwiki's internal representation of a
|
||||
dependency type from one or more of these keywords:
|
||||
|
||||
* `content` is the default. Any change to the content
|
||||
of a page triggers the dependency.
|
||||
* `presence` is only triggered by a change to the presence
|
||||
of a page.
|
||||
* `links` is only triggered by a change to the links of a page.
|
||||
This includes when a link is added, removed, or changes what
|
||||
it points to due to other changes. It does not include the
|
||||
addition or removal of a duplicate link.
|
||||
|
||||
If multiple types are specified, they are combined.
|
||||
|
||||
#### `use_pagespec($$;@)`
|
||||
|
||||
Passed a page name, and [[ikiwiki/PageSpec]], returns a list of pages
|
||||
in the wiki that match the [[ikiwiki/PageSpec]].
|
||||
|
||||
The page will automatically be made to depend on the specified
|
||||
[[ikiwiki/PageSpec]], so `add_depends` does not need to be called. This
|
||||
is significantly more efficient than calling `add_depends`
|
||||
followed by `pagespec_match_list`. You should use this anytime a plugin
|
||||
needs to match a set of pages and generate something based on that list.
|
||||
|
||||
Additional named parameters can be specified:
|
||||
|
||||
* `deptype` optionally specifies the type of dependency to add. Use the
|
||||
`deptype` function to generate a dependency type.
|
||||
* `limit` is a reference to a function, that is called and passed a page,
|
||||
and must return true for the page to be included.
|
||||
* `sort` specifies a sort order for the list. See
|
||||
[[ikiwiki/PageSpec/sorting]] for the avilable sort methods.
|
||||
* `reverse` if true, sorts in reverse.
|
||||
* `num` if nonzero, specifies the maximum number of matching pages that
|
||||
will be returned.
|
||||
|
||||
#### `add_depends($$;$)`
|
||||
|
||||
Makes the specified page depend on the specified [[ikiwiki/PageSpec]].
|
||||
|
||||
By default, dependencies are full content dependencies, meaning that the
|
||||
page will be updated whenever anything matching the PageSpec is modified.
|
||||
This default can be overridden by additional named parameters, which can be
|
||||
used to indicate weaker types of dependencies:
|
||||
|
||||
* `presence` if set to true, only the presence of a matching page triggers
|
||||
the dependency.
|
||||
* `links` if set to true, any change to links on a matching page
|
||||
triggers the dependency. This includes when a link is added, removed,
|
||||
or changes what it points to due to other changes. It does not include
|
||||
the addition or removal of a duplicate link.
|
||||
This can be overridden by passing a `deptype` value as the third parameter.
|
||||
|
||||
#### `pagespec_match($$;@)`
|
||||
|
||||
|
@ -984,10 +1015,12 @@ IkiWiki::ErrorReason object explaining why.
|
|||
|
||||
When constructing these objects, you should also include information about
|
||||
of any pages whose contents or other metadata influenced the result of the
|
||||
match. For example, "backlink(foo)" is influenced by the contents of page foo;
|
||||
"link(foo)" and "title(bar)" are influenced by the contents of any
|
||||
page they match; "created_before(foo)" is influenced by the metadata of
|
||||
foo; while "glob(*)" is not influenced by the contents of any page.
|
||||
match. Do this by passing a list of pages, followed by `deptype` values.
|
||||
|
||||
For example, "backlink(foo)" is influenced by the contents of page foo;
|
||||
"link(foo)" and "title(bar)" are influenced by the contents of any page
|
||||
they match; "created_before(foo)" is influenced by the metadata of foo;
|
||||
while "glob(*)" is not influenced by the contents of any page.
|
||||
|
||||
### Setup plugins
|
||||
|
||||
|
|
|
@ -0,0 +1,30 @@
|
|||
#!/usr/bin/perl
|
||||
use warnings;
|
||||
use strict;
|
||||
use Test::More tests => 64;
|
||||
|
||||
BEGIN { use_ok("IkiWiki"); }
|
||||
|
||||
%pagesources=(
|
||||
foo => "foo.mdwn",
|
||||
bar => "bar.mdwn",
|
||||
"post/1" => "post/1.mdwn",
|
||||
"post/2" => "post/2.mdwn",
|
||||
"post/3" => "post/3.mdwn",
|
||||
);
|
||||
|
||||
is_deeply([use_pagespec("foo", "bar")], ["bar"]);
|
||||
is_deeply([sort(use_pagespec("foo", "post/*"))], ["post/1", "post/2", "post/3"]);
|
||||
is_deeply([use_pagespec("foo", "post/*", sort => "title", reverse => 1)],
|
||||
["post/3", "post/2", "post/1"]);
|
||||
is_deeply([use_pagespec("foo", "post/*", sort => "title", num => 2)],
|
||||
["post/1", "post/2"]);
|
||||
is_deeply([use_pagespec("foo", "post/*", sort => "title", num => 50)],
|
||||
["post/1", "post/2", "post/3"]);
|
||||
is_deeply([use_pagespec("foo", "post/*", sort => "title",
|
||||
limit => sub { $_[0] !~ /3/}) ],
|
||||
["post/1", "post/2"]);
|
||||
eval { use_pagespec("foo", "beep") };
|
||||
ok($@, "fails with error when unable to match anything");
|
||||
eval { use_pagespec("foo", "this is not a legal pagespec!") };
|
||||
ok($@, "fails with error when pagespec bad");
|
Loading…
Reference in New Issue