From 71eabd44d5749ec5000e4f32c8dfc19a16aef297 Mon Sep 17 00:00:00 2001 From: Joey Hess Date: Fri, 2 Oct 2009 15:38:04 -0400 Subject: handle transitive dependencies by re-running dep resolver This is a rather expensive solution to the transitive dependency problem. --- IkiWiki/Render.pm | 81 +++++++++++++++++++++++++++++-------------------------- 1 file changed, 43 insertions(+), 38 deletions(-) diff --git a/IkiWiki/Render.pm b/IkiWiki/Render.pm index 246c2260d..c58f33d68 100644 --- a/IkiWiki/Render.pm +++ b/IkiWiki/Render.pm @@ -455,50 +455,55 @@ sub refresh () { } if (%rendered || @del || @internal) { - my @changed=(keys %rendered, @del); - - my %lcchanged = map { lc(pagename($_)) => 1 } @changed; - - # rebuild dependant pages - foreach my $f (@$files) { - next if $rendered{$f}; - my $p=pagename($f); - my $reason = undef; - - if (exists $depends_simple{$p}) { - foreach my $d (keys %{$depends_simple{$p}}) { - if (exists $lcchanged{$d}) { - $reason = $d; - last; + my @changed; + my $changes; + do { + $changes=0; + @changed=(keys %rendered, @del); + my %lcchanged = map { lc(pagename($_)) => 1 } @changed; + + # rebuild dependant pages + foreach my $f (@$files) { + next if $rendered{$f}; + my $p=pagename($f); + my $reason = undef; + + if (exists $depends_simple{$p}) { + foreach my $d (keys %{$depends_simple{$p}}) { + if (exists $lcchanged{$d}) { + $reason = $d; + last; + } } } - } - - if (exists $depends{$p} && ! defined $reason) { - D: foreach my $d (keys %{$depends{$p}}) { - my $sub=pagespec_translate($d); - next if $@ || ! defined $sub; - - # only consider internal files - # if the page explicitly depends - # on such files - foreach my $file (@changed, $d =~ /internal\(/ ? @internal : ()) { - next if $file eq $f; - my $page=pagename($file); - if ($sub->($page, location => $p)) { - $reason = $page; - last D; + + if (exists $depends{$p} && ! defined $reason) { + D: foreach my $d (keys %{$depends{$p}}) { + my $sub=pagespec_translate($d); + next if $@ || ! defined $sub; + + # only consider internal files + # if the page explicitly depends + # on such files + foreach my $file (@changed, $d =~ /internal\(/ ? @internal : ()) { + next if $file eq $f; + my $page=pagename($file); + if ($sub->($page, location => $p)) { + $reason = $page; + last D; + } } } } + + if (defined $reason) { + debug(sprintf(gettext("building %s, which depends on %s"), $f, $reason)); + render($f); + $rendered{$f}=1; + $changes++; + } } - - if (defined $reason) { - debug(sprintf(gettext("building %s, which depends on %s"), $f, $reason)); - render($f); - $rendered{$f}=1; - } - } + } while $changes; # handle backlinks; if a page has added/removed links, # update the pages it links to -- cgit v1.2.3 From 52134dc0ef22d4848ea90042be12175788ac4348 Mon Sep 17 00:00:00 2001 From: Joey Hess Date: Fri, 2 Oct 2009 15:41:09 -0400 Subject: minor optimisation As soon as a change happens, we know we will need to rescan all dependencies from the start, so bail out of the current scan partway to avoid doing redundant work. Only problem with this is that ikiwiki sometimes ends up printing out dependencies that, while correct, are not obvious. Before: building B, which depends on A building C, which depends on A building D, which depends on A After: building B, which depends on A building C, which depends on B building D, which depends on C --- IkiWiki/Render.pm | 1 + 1 file changed, 1 insertion(+) diff --git a/IkiWiki/Render.pm b/IkiWiki/Render.pm index c58f33d68..09b646f75 100644 --- a/IkiWiki/Render.pm +++ b/IkiWiki/Render.pm @@ -501,6 +501,7 @@ sub refresh () { render($f); $rendered{$f}=1; $changes++; + last; } } } while $changes; -- cgit v1.2.3 From 743f69c675de6bdf240a2980e0924ed9d3bb782b Mon Sep 17 00:00:00 2001 From: Joey Hess Date: Sat, 3 Oct 2009 15:31:51 -0400 Subject: add dependency type parameters to add_depends Dependency types are represented by bits in the values of the %depends and %depends_simple hashes. Change the dependslist array saved to the index to a depends hash. depends_simple is also converted from an array to a hash. Note that the depends field used to be a string, and we still have compat code to handle upgrades from that, as well as from the arrays. I didn't use ikiwiki-transition because I don't want ikiwiki to break if users forget to run it; also we're going to recommend a full rebuild on upgrade to this version to get the improved dependency handling. So this compat code can be removed or moved to ikiwiki-transition later. --- IkiWiki.pm | 38 ++++++++++++++++++++++++++++++-------- 1 file changed, 30 insertions(+), 8 deletions(-) diff --git a/IkiWiki.pm b/IkiWiki.pm index 2637f6017..67149bc8b 100644 --- a/IkiWiki.pm +++ b/IkiWiki.pm @@ -28,6 +28,10 @@ our $VERSION = 3.00; # plugin interface version, next is ikiwiki version our $version='unknown'; # VERSION_AUTOREPLACE done by Makefile, DNE our $installdir='/usr'; # INSTALLDIR_AUTOREPLACE done by Makefile, DNE +# Page dependency types. +our $DEPEND_EXISTS=1; +our $DEPEND_CONTENT=2; + # Optimisation. use Memoize; memoize("abs2rel"); @@ -1524,18 +1528,28 @@ sub loadindex () { $links{$page}=$d->{links}; $oldlinks{$page}=[@{$d->{links}}]; } - if (exists $d->{depends_simple}) { + if (ref $d->{depends_simple} eq 'ARRAY') { + # old format $depends_simple{$page}={ map { $_ => 1 } @{$d->{depends_simple}} }; } + elsif (exists $d->{depends_simple}) { + $depends{$page}=$d->{depends_simple}; + } if (exists $d->{dependslist}) { + # old format $depends{$page}={ - map { $_ => 1 } @{$d->{dependslist}} + map { $_ => $DEPEND_CONTENT | $DEPEND_EXISTS } + @{$d->{dependslist}} }; } + elsif (exists $d->{depends} && ! ref $d->{depends}) { + # old format + $depends{$page}={$d->{depends} => $DEPEND_CONTENT | $DEPEND_EXISTS}; + } elsif (exists $d->{depends}) { - $depends{$page}={$d->{depends} => 1}; + $depends{$page}=$d->{depends}; } if (exists $d->{state}) { $pagestate{$page}=$d->{state}; @@ -1581,11 +1595,11 @@ sub saveindex () { }; if (exists $depends{$page}) { - $index{page}{$src}{dependslist} = [ keys %{$depends{$page}} ]; + $index{page}{$src}{depends} = $depends{$page}; } if (exists $depends_simple{$page}) { - $index{page}{$src}{depends_simple} = [ keys %{$depends_simple{$page}} ]; + $index{page}{$src}{depends_simple} = $depends_simple{$page}; } if (exists $pagestate{$page}) { @@ -1753,20 +1767,28 @@ sub rcs_receive () { $hooks{rcs}{rcs_receive}{call}->(); } -sub add_depends ($$) { +sub add_depends ($$;@) { my $page=shift; my $pagespec=shift; + my $deptype=$DEPEND_CONTENT | $DEPEND_EXISTS; + if (@_) { + my %params=@_; + if (defined $params{content} && $params{content} == 0) { + $deptype=$deptype & ~$DEPEND_CONTENT; + } + } + if ($pagespec =~ /$config{wiki_file_regexp}/ && $pagespec !~ /[\s*?()!]/) { # a simple dependency, which can be matched by string eq - $depends_simple{$page}{lc $pagespec} = 1; + $depends_simple{$page}{lc $pagespec} |= $deptype; return 1; } return unless pagespec_valid($pagespec); - $depends{$page}{$pagespec} = 1; + $depends{$page}{$pagespec} |= $deptype; return 1; } -- cgit v1.2.3 From dc4e44adf13bc20c0a801f2b176370f330841098 Mon Sep 17 00:00:00 2001 From: Joey Hess Date: Sat, 3 Oct 2009 15:36:23 -0400 Subject: pagecount: Use contentless dependency This will avoid lots of unnecessary updates of pages using the pagecount directive. Yay! --- IkiWiki/Plugin/pagecount.pm | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/IkiWiki/Plugin/pagecount.pm b/IkiWiki/Plugin/pagecount.pm index 5a2301af4..17eda0618 100644 --- a/IkiWiki/Plugin/pagecount.pm +++ b/IkiWiki/Plugin/pagecount.pm @@ -23,8 +23,8 @@ sub preprocess (@) { $params{pages}="*" unless defined $params{pages}; # Needs to update count whenever a page is added or removed, so - # register a dependency. - add_depends($params{page}, $params{pages}); + # register a contentless dependency. + add_depends($params{page}, $params{pages}, content => 0); my @pages; if ($params{pages} eq "*") { -- cgit v1.2.3 From 5c9f65a67294e3e7b2759306c182b7eedc93093d Mon Sep 17 00:00:00 2001 From: Joey Hess Date: Sat, 3 Oct 2009 15:37:15 -0400 Subject: set dependency hash value properly for new dependency types Just "1" won't cut it anymore; we need to list all the dependency types. --- ikiwiki-transition | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ikiwiki-transition b/ikiwiki-transition index 8a20cf655..c50a748e8 100755 --- a/ikiwiki-transition +++ b/ikiwiki-transition @@ -299,7 +299,7 @@ sub oldloadindex { $pagemtime{$page}=$items{mtime}[0]; $oldlinks{$page}=[@{$items{link}}]; $links{$page}=[@{$items{link}}]; - $depends{$page}={ $items{depends}[0] => 1 } if exists $items{depends}; + $depends{$page}={ $items{depends}[0] => $IkiWiki::DEPEND_CONTENT | $IkiWiki::DEPEND_EXISTS } if exists $items{depends}; $destsources{$_}=$page foreach @{$items{dest}}; $renderedfiles{$page}=[@{$items{dest}}]; $pagecase{lc $page}=$page; -- cgit v1.2.3 From fd9d9680242c0d1c835fc56f969f8e2a2618a5de Mon Sep 17 00:00:00 2001 From: Joey Hess Date: Sat, 3 Oct 2009 15:37:57 -0400 Subject: document add_depends dependency type interface --- doc/plugins/write.mdwn | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/doc/plugins/write.mdwn b/doc/plugins/write.mdwn index 668f8d8b6..c244c1f2f 100644 --- a/doc/plugins/write.mdwn +++ b/doc/plugins/write.mdwn @@ -609,10 +609,17 @@ 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($$)` +#### `add_depends($$;@)` Makes the specified page depend on the specified [[ikiwiki/PageSpec]]. +Additional named parameters can be passed, to indicate what type of +dependency this is. + +Currently, only a "content" parameter is specified. If set to 0, the +dependency does not involve the content of pages matching the PageSpec, but +only their existence. + #### `pagespec_match($$;@)` Passed a page name, and [[ikiwiki/PageSpec]], returns true if the -- cgit v1.2.3 From 49b71d0615f3ec995e8958ede6baaae8524d1986 Mon Sep 17 00:00:00 2001 From: Joey Hess Date: Sat, 3 Oct 2009 15:38:18 -0400 Subject: update --- debian/changelog | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/debian/changelog b/debian/changelog index ca5409af7..bec1a61d3 100644 --- a/debian/changelog +++ b/debian/changelog @@ -10,6 +10,12 @@ ikiwiki (3.14159266) UNRELEASED; urgency=low * mirrorlist: Display nothing if list is empty. * Fix a bug that could lead to duplicate links being recorded for tags. + * Added support framework for multiple types of dependencies. + * Allow declaring that a dependency does not encompass the content of a + page. (By passing content => 0 to add_depends.) + * pagecount: Use a contentless dependency, which makes this + directive much less expensive to use, since page edits will + no longer trigger an unnecessary update of the page count. -- Joey Hess Sun, 27 Sep 2009 17:40:03 -0400 -- cgit v1.2.3 From 26dbc09bd88ba6c33c18995c2b028726c370012f Mon Sep 17 00:00:00 2001 From: Joey Hess Date: Sat, 3 Oct 2009 15:46:53 -0400 Subject: implement support for DEPEND_EXISTS Preliminary support, anyway. If a dependency only includes DEPEND_EXISTS, then only changes that involved adding or deleting a page can trigger it. This is complicated by internal pages, since the code did not previously differentiate between add, delete, and change of internal pages. Now it tracks change separately from add+delete, so DEPEND_EXISTS pagespecs that actually match internal pages (which will probably be quite rare in practice) should work. --- IkiWiki/Render.pm | 38 +++++++++++++++++++++++++++++++------- 1 file changed, 31 insertions(+), 7 deletions(-) diff --git a/IkiWiki/Render.pm b/IkiWiki/Render.pm index 246c2260d..9e00428c2 100644 --- a/IkiWiki/Render.pm +++ b/IkiWiki/Render.pm @@ -342,7 +342,7 @@ sub refresh () { run_hooks(refresh => sub { shift->() }); my ($files, $exists)=find_src_files(); - my (%rendered, @add, @del, @internal); + my (%rendered, @add, @del, @internal, @internal_change); # check for added or removed pages foreach my $file (@$files) { my $page=pagename($file); @@ -407,7 +407,7 @@ sub refresh () { $forcerebuild{$page}) { $pagemtime{$page}=$stat[9]; if (isinternal($page)) { - push @internal, $file; + push @internal_change, $file; # Preprocess internal page in scan-only mode. preprocess($page, $page, readfile($srcfile), 1); } @@ -429,7 +429,7 @@ sub refresh () { render($file); $rendered{$file}=1; } - foreach my $file (@internal) { + foreach my $file (@internal, @internal_change) { # internal pages are not rendered my $page=pagename($file); delete $depends{$page}; @@ -454,10 +454,12 @@ sub refresh () { } } - if (%rendered || @del || @internal) { + if (%rendered || @del || @internal || @internal_change) { my @changed=(keys %rendered, @del); + my @exists_changed=(@add, @del); - my %lcchanged = map { lc(pagename($_)) => 1 } @changed; + my %lc_changed = map { lc(pagename($_)) => 1 } @changed; + my %lc_exists_changed = map { lc(pagename($_)) => 1 } @exists_changed; # rebuild dependant pages foreach my $f (@$files) { @@ -467,7 +469,13 @@ sub refresh () { if (exists $depends_simple{$p}) { foreach my $d (keys %{$depends_simple{$p}}) { - if (exists $lcchanged{$d}) { + if ($depends_simple{$p}{$d} == $IkiWiki::DEPEND_EXISTS) { + if (exists $lc_exists_changed{$d}) { + $reason = $d; + last; + } + } + elsif (exists $lc_changed{$d}) { $reason = $d; last; } @@ -479,10 +487,26 @@ sub refresh () { my $sub=pagespec_translate($d); next if $@ || ! defined $sub; + my @candidates; + if ($depends{$p}{$d} == $IkiWiki::DEPEND_EXISTS) { + @candidates=@exists_changed; + } + else { + @candidates=@changed; + } # only consider internal files # if the page explicitly depends # on such files - foreach my $file (@changed, $d =~ /internal\(/ ? @internal : ()) { + if ($d =~ /internal\(/) { + if ($depends{$p}{$d} == $IkiWiki::DEPEND_EXISTS) { + push @candidates, @internal; + } + else { + push @candidates, @internal, @internal_change; + } + } + + foreach my $file (@candidates) { next if $file eq $f; my $page=pagename($file); if ($sub->($page, location => $p)) { -- cgit v1.2.3 From 6eaf9e40154050936ad9184d64295664da2cc83c Mon Sep 17 00:00:00 2001 From: Joey Hess Date: Sat, 3 Oct 2009 15:55:11 -0400 Subject: orphans and brokenlinks cannot use contentless dependency Tried a contentless dep and it does not work; changes to links in pages are not noticed. Drat. --- IkiWiki/Plugin/brokenlinks.pm | 4 ++-- IkiWiki/Plugin/orphans.pm | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/IkiWiki/Plugin/brokenlinks.pm b/IkiWiki/Plugin/brokenlinks.pm index eb698b0be..b8ed2b8de 100644 --- a/IkiWiki/Plugin/brokenlinks.pm +++ b/IkiWiki/Plugin/brokenlinks.pm @@ -23,8 +23,8 @@ sub preprocess (@) { my %params=@_; $params{pages}="*" unless defined $params{pages}; - # Needs to update whenever a page is added or removed, so - # register a dependency. + # Needs to update whenever a page is changed, + # added or removed, in order to see the link changes. add_depends($params{page}, $params{pages}); my @broken; diff --git a/IkiWiki/Plugin/orphans.pm b/IkiWiki/Plugin/orphans.pm index 711226772..d981670e7 100644 --- a/IkiWiki/Plugin/orphans.pm +++ b/IkiWiki/Plugin/orphans.pm @@ -23,8 +23,8 @@ sub preprocess (@) { my %params=@_; $params{pages}="*" unless defined $params{pages}; - # Needs to update whenever a page is added or removed, so - # register a dependency. + # Needs to update whenever a page is changed, added, or removed, + # in order to see the link changes. add_depends($params{page}, $params{pages}); my @orphans; -- cgit v1.2.3 From 5fd230f9688bf7400f5ef962073bac8bc031e738 Mon Sep 17 00:00:00 2001 From: Joey Hess Date: Sun, 4 Oct 2009 15:34:42 -0400 Subject: detect pagespecs that require content dependencies When adding a contentless dependency, the pagespec also needs to be one that does not look at any page content information. As a first approximation of that, only allow glob-based pagespecs in contentless dependencies. While there are probably a few other types of pagespecs that can match contentless, this will work for most of them. --- IkiWiki.pm | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/IkiWiki.pm b/IkiWiki.pm index 67149bc8b..56e2d4e71 100644 --- a/IkiWiki.pm +++ b/IkiWiki.pm @@ -1774,7 +1774,8 @@ sub add_depends ($$;@) { my $deptype=$DEPEND_CONTENT | $DEPEND_EXISTS; if (@_) { my %params=@_; - if (defined $params{content} && $params{content} == 0) { + if (defined $params{content} && $params{content} == 0 && + pagespec_contentless($pagespec)) { $deptype=$deptype & ~$DEPEND_CONTENT; } } @@ -1974,6 +1975,20 @@ sub pagespec_valid ($) { return ! $@; } +sub pagespec_contentless ($) { + my $spec=shift; + + while ($spec=~m{ + (\w+)\([^\)]*\) # only match pagespec functions + }igx) { + # only glob and internal can be matched contentless + # (first approximation) + return 0 if $1 ne "glob" && $1 ne "internal"; + } + + return 1; +} + sub glob2re ($) { my $re=quotemeta(shift); $re=~s/\\\*/.*/g; -- cgit v1.2.3 From daafdf1acb426e0abae218a04c8b22e8b9885354 Mon Sep 17 00:00:00 2001 From: Joey Hess Date: Sun, 4 Oct 2009 15:43:38 -0400 Subject: optimise add_depends for simple pagespecs We don't need to check if the pagespec is contentless; all simple ones are. --- IkiWiki.pm | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/IkiWiki.pm b/IkiWiki.pm index 56e2d4e71..c059a9b9f 100644 --- a/IkiWiki.pm +++ b/IkiWiki.pm @@ -1771,18 +1771,19 @@ sub add_depends ($$;@) { my $page=shift; my $pagespec=shift; + my $simple=$pagespec =~ /$config{wiki_file_regexp}/ && + $pagespec !~ /[\s*?()!]/; + my $deptype=$DEPEND_CONTENT | $DEPEND_EXISTS; if (@_) { my %params=@_; if (defined $params{content} && $params{content} == 0 && - pagespec_contentless($pagespec)) { + ($simple || pagespec_contentless($pagespec))) { $deptype=$deptype & ~$DEPEND_CONTENT; } } - if ($pagespec =~ /$config{wiki_file_regexp}/ && - $pagespec !~ /[\s*?()!]/) { - # a simple dependency, which can be matched by string eq + if ($simple) { $depends_simple{$page}{lc $pagespec} |= $deptype; return 1; } -- cgit v1.2.3 From 2fbfcd16e6d5717fea7b23d7fa82961222a6e32f Mon Sep 17 00:00:00 2001 From: Joey Hess Date: Sun, 4 Oct 2009 15:46:23 -0400 Subject: map: Use a contentless dependency unless show= is specified. This makes simple maps efficient enough that they can be used on sidebars! --- IkiWiki/Plugin/map.pm | 8 ++++---- debian/changelog | 2 ++ 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/IkiWiki/Plugin/map.pm b/IkiWiki/Plugin/map.pm index 54146dc46..682960777 100644 --- a/IkiWiki/Plugin/map.pm +++ b/IkiWiki/Plugin/map.pm @@ -68,13 +68,13 @@ sub preprocess (@) { } # Needs to update whenever a page is added or removed (or in some - # cases, when its content changes, if show=title), so register a - # dependency. - add_depends($params{page}, $params{pages}); + # cases, when its content changes, if show= is specified), so + # register a dependency. + add_depends($params{page}, $params{pages}, content => exists $params{show}); # Explicitly add all currently shown pages, to detect when pages # are removed. foreach my $item (keys %mapitems) { - add_depends($params{page}, $item); + add_depends($params{page}, $item, content => exists $params{show}); } # Create the map. diff --git a/debian/changelog b/debian/changelog index bec1a61d3..ae39d4847 100644 --- a/debian/changelog +++ b/debian/changelog @@ -16,6 +16,8 @@ ikiwiki (3.14159266) UNRELEASED; urgency=low * pagecount: Use a contentless dependency, which makes this directive much less expensive to use, since page edits will no longer trigger an unnecessary update of the page count. + * map: Use a contentless dependency unless show= is specified. + This makes simple maps efficient enough that they can be used on sidebars! -- Joey Hess Sun, 27 Sep 2009 17:40:03 -0400 -- cgit v1.2.3 From da5c12e9ebb6bad5e73b0b709d0bcc82657ac8e3 Mon Sep 17 00:00:00 2001 From: Joey Hess Date: Sun, 4 Oct 2009 16:01:56 -0400 Subject: expand the set of things that can be matched contentless --- IkiWiki.pm | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/IkiWiki.pm b/IkiWiki.pm index c059a9b9f..5e5dc739d 100644 --- a/IkiWiki.pm +++ b/IkiWiki.pm @@ -1982,9 +1982,7 @@ sub pagespec_contentless ($) { while ($spec=~m{ (\w+)\([^\)]*\) # only match pagespec functions }igx) { - # only glob and internal can be matched contentless - # (first approximation) - return 0 if $1 ne "glob" && $1 ne "internal"; + return 0 unless $1=~/^(glob|internal|creation_month|creation_day|creation_year|created_before|created_after)$/; } return 1; -- cgit v1.2.3 From e529c561f548fa2d277b8cb7c123c3a46a0427a4 Mon Sep 17 00:00:00 2001 From: Joey Hess Date: Sun, 4 Oct 2009 16:03:01 -0400 Subject: inline: Use a contentless dependency in quick mode. --- IkiWiki/Plugin/inline.pm | 7 +++---- debian/changelog | 1 + 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/IkiWiki/Plugin/inline.pm b/IkiWiki/Plugin/inline.pm index ccfadfd69..5133c4ba6 100644 --- a/IkiWiki/Plugin/inline.pm +++ b/IkiWiki/Plugin/inline.pm @@ -197,7 +197,7 @@ sub preprocess_inline (@) { split ' ', $params{pagenames}; } else { - add_depends($params{page}, $params{pages}); + add_depends($params{page}, $params{pages}, content => ! $quick); @list = pagespec_match_list( [ grep { $_ ne $params{page} } keys %pagesources ], @@ -248,10 +248,9 @@ sub preprocess_inline (@) { } # Explicitly add all currently displayed pages as dependencies, so - # that if they are removed or otherwise changed, the inline will be - # sure to be updated. + # that if they are removed, the inline will be sure to be updated. foreach my $p ($#list >= $#feedlist ? @list : @feedlist) { - add_depends($params{page}, $p); + add_depends($params{page}, $p, content => ! $quick); } if ($feeds && exists $params{feedpages}) { diff --git a/debian/changelog b/debian/changelog index ae39d4847..9d03ae990 100644 --- a/debian/changelog +++ b/debian/changelog @@ -18,6 +18,7 @@ ikiwiki (3.14159266) UNRELEASED; urgency=low no longer trigger an unnecessary update of the page count. * map: Use a contentless dependency unless show= is specified. This makes simple maps efficient enough that they can be used on sidebars! + * inline: Use a contentless dependency in quick mode. -- Joey Hess Sun, 27 Sep 2009 17:40:03 -0400 -- cgit v1.2.3 From a6689f9c7a1ecad02b51962c0858df47352c4648 Mon Sep 17 00:00:00 2001 From: Joey Hess Date: Sun, 4 Oct 2009 16:05:41 -0400 Subject: calendar: all dependencies are contentless --- IkiWiki/Plugin/calendar.pm | 21 ++++++++++++--------- debian/changelog | 6 +++--- 2 files changed, 15 insertions(+), 12 deletions(-) diff --git a/IkiWiki/Plugin/calendar.pm b/IkiWiki/Plugin/calendar.pm index 5d16dff75..a5cc20882 100644 --- a/IkiWiki/Plugin/calendar.pm +++ b/IkiWiki/Plugin/calendar.pm @@ -104,19 +104,22 @@ sub format_month (@) { "$archivebase/$year/".sprintf("%02d", $month), linktext => " $monthname "); } - add_depends($params{page}, "$archivebase/$year/".sprintf("%02d", $month)); + add_depends($params{page}, "$archivebase/$year/".sprintf("%02d", $month), + content => 0); if (exists $cache{$pagespec}{"$pyear/$pmonth"}) { $purl = htmllink($params{page}, $params{destpage}, "$archivebase/$pyear/" . sprintf("%02d", $pmonth), linktext => " $pmonthname "); } - add_depends($params{page}, "$archivebase/$pyear/".sprintf("%02d", $pmonth)); + add_depends($params{page}, "$archivebase/$pyear/".sprintf("%02d", $pmonth), + content => 0); if (exists $cache{$pagespec}{"$nyear/$nmonth"}) { $nurl = htmllink($params{page}, $params{destpage}, "$archivebase/$nyear/" . sprintf("%02d", $nmonth), linktext => " $nmonthname "); } - add_depends($params{page}, "$archivebase/$nyear/".sprintf("%02d", $nmonth)); + add_depends($params{page}, "$archivebase/$nyear/".sprintf("%02d", $nmonth), + content => 0); # Start producing the month calendar $calendar=< 0); # Explicitly add all currently linked pages as dependencies, so # that if they are removed, the calendar will be sure to be updated. foreach my $p (@list) { - add_depends($params{page}, $p); + add_depends($params{page}, $p, content => 0); } return $calendar; @@ -246,19 +249,19 @@ sub format_year (@) { "$archivebase/$year", linktext => "$year"); } - add_depends($params{page}, "$archivebase/$year"); + add_depends($params{page}, "$archivebase/$year", content => 0); if (exists $cache{$pagespec}{"$pyear"}) { $purl = htmllink($params{page}, $params{destpage}, "$archivebase/$pyear", linktext => "\←"); } - add_depends($params{page}, "$archivebase/$pyear"); + add_depends($params{page}, "$archivebase/$pyear", content => 0); if (exists $cache{$pagespec}{"$nyear"}) { $nurl = htmllink($params{page}, $params{destpage}, "$archivebase/$nyear", linktext => "\→"); } - add_depends($params{page}, "$archivebase/$nyear"); + add_depends($params{page}, "$archivebase/$nyear", content => 0); # Start producing the year calendar $calendar=<$monthabbr\n}; } - add_depends($params{page}, "$archivebase/$year/$mtag"); + add_depends($params{page}, "$archivebase/$year/$mtag", content => 0); $calendar.=qq{\t\n} if ($month % $params{months_per_row} == 0); } diff --git a/debian/changelog b/debian/changelog index 9d03ae990..1a76303b1 100644 --- a/debian/changelog +++ b/debian/changelog @@ -13,9 +13,9 @@ ikiwiki (3.14159266) UNRELEASED; urgency=low * Added support framework for multiple types of dependencies. * Allow declaring that a dependency does not encompass the content of a page. (By passing content => 0 to add_depends.) - * pagecount: Use a contentless dependency, which makes this - directive much less expensive to use, since page edits will - no longer trigger an unnecessary update of the page count. + * pagecount, calendar: Use a contentless dependency, which makes these + directives much less expensive to use, since page edits will + no longer trigger an unnecessary update. * map: Use a contentless dependency unless show= is specified. This makes simple maps efficient enough that they can be used on sidebars! * inline: Use a contentless dependency in quick mode. -- cgit v1.2.3 From ce78b699278be0797316518079474bc776d657ed Mon Sep 17 00:00:00 2001 From: Joey Hess Date: Sun, 4 Oct 2009 16:07:02 -0400 Subject: edittemplate: contentless dependency This one is unlikely to matter much, but yeah, it's contentless. --- IkiWiki/Plugin/edittemplate.pm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/IkiWiki/Plugin/edittemplate.pm b/IkiWiki/Plugin/edittemplate.pm index 0bafc95d0..89d450725 100644 --- a/IkiWiki/Plugin/edittemplate.pm +++ b/IkiWiki/Plugin/edittemplate.pm @@ -58,7 +58,7 @@ sub preprocess (@) { $pagestate{$params{page}}{edittemplate}{$params{match}}=$link; return "" if ($params{silent} && IkiWiki::yesno($params{silent})); - add_depends($params{page}, $link); + add_depends($params{page}, $link, content => 0); return sprintf(gettext("edittemplate %s registered for %s"), htmllink($params{page}, $params{destpage}, $link), $params{match}); -- cgit v1.2.3 From de6eba6ddde9f6d4577b49b204dcdd9f1a203ed4 Mon Sep 17 00:00:00 2001 From: Joey Hess Date: Sun, 4 Oct 2009 16:10:34 -0400 Subject: not a contentless dependency needs link info --- IkiWiki/Plugin/linkmap.pm | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/IkiWiki/Plugin/linkmap.pm b/IkiWiki/Plugin/linkmap.pm index 941ed5f36..d0671ae0e 100644 --- a/IkiWiki/Plugin/linkmap.pm +++ b/IkiWiki/Plugin/linkmap.pm @@ -28,8 +28,8 @@ sub preprocess (@) { $params{pages}="*" unless defined $params{pages}; - # Needs to update whenever a page is added or removed, so - # register a dependency. + # Needs to update whenever a page is added, removed, or + # its links change, so register a dependency. add_depends($params{page}, $params{pages}); # Can't just return the linkmap here, since the htmlscrubber -- cgit v1.2.3 From 2af988b86fca6d2ca9476ae698cf1e840969af78 Mon Sep 17 00:00:00 2001 From: Joey Hess Date: Sun, 4 Oct 2009 16:11:10 -0400 Subject: listdirectives: contentless dependency Another one that probably doesn't matter, but for completness. --- IkiWiki/Plugin/listdirectives.pm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/IkiWiki/Plugin/listdirectives.pm b/IkiWiki/Plugin/listdirectives.pm index bd73f1a04..96150f986 100644 --- a/IkiWiki/Plugin/listdirectives.pm +++ b/IkiWiki/Plugin/listdirectives.pm @@ -84,7 +84,7 @@ sub preprocess (@) { foreach my $plugin (@pluginlist) { $result .= '
  • '; my $link=linkpage($config{directive_description_dir}."/".$plugin); - add_depends($params{page}, $link); + add_depends($params{page}, $link, content => 0); $result .= htmllink($params{page}, $params{destpage}, $link); $result .= '
  • '; } -- cgit v1.2.3 From 66852de77553a6131569436d4531c69a4515a4d3 Mon Sep 17 00:00:00 2001 From: Joey Hess Date: Sun, 4 Oct 2009 16:12:05 -0400 Subject: meta redir dependency is contentless --- IkiWiki/Plugin/meta.pm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/IkiWiki/Plugin/meta.pm b/IkiWiki/Plugin/meta.pm index 514b09369..eef3013a0 100644 --- a/IkiWiki/Plugin/meta.pm +++ b/IkiWiki/Plugin/meta.pm @@ -195,7 +195,7 @@ sub preprocess (@) { if (! length $link) { error gettext("redir page not found") } - add_depends($page, $link); + add_depends($page, $link, content => 0); $value=urlto($link, $page); $value.='#'.$redir_anchor if defined $redir_anchor; -- cgit v1.2.3 From 7982c3c1773feef0d7f248ff3efe09dd2cd94ad8 Mon Sep 17 00:00:00 2001 From: Joey Hess Date: Sun, 4 Oct 2009 16:16:50 -0400 Subject: postsparkline and progress: also contentless dependencies --- IkiWiki/Plugin/postsparkline.pm | 2 +- IkiWiki/Plugin/progress.pm | 4 ++-- debian/changelog | 6 +++--- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/IkiWiki/Plugin/postsparkline.pm b/IkiWiki/Plugin/postsparkline.pm index d2e5c2378..694d39575 100644 --- a/IkiWiki/Plugin/postsparkline.pm +++ b/IkiWiki/Plugin/postsparkline.pm @@ -48,7 +48,7 @@ sub preprocess (@) { error gettext("unknown formula"); } - add_depends($params{page}, $params{pages}); + add_depends($params{page}, $params{pages}, content => 0); my @list=sort { $params{timehash}->{$b} <=> $params{timehash}->{$a} } pagespec_match_list( diff --git a/IkiWiki/Plugin/progress.pm b/IkiWiki/Plugin/progress.pm index 76d994acc..3b664f4cb 100644 --- a/IkiWiki/Plugin/progress.pm +++ b/IkiWiki/Plugin/progress.pm @@ -36,8 +36,8 @@ sub preprocess (@) { $fill.="%"; } elsif (defined $params{totalpages} and defined $params{donepages}) { - add_depends($params{page}, $params{totalpages}); - add_depends($params{page}, $params{donepages}); + add_depends($params{page}, $params{totalpages}, content => 0); + add_depends($params{page}, $params{donepages}, content => 0); my @pages=keys %pagesources; my $totalcount=0; diff --git a/debian/changelog b/debian/changelog index 1a76303b1..0e9bf512b 100644 --- a/debian/changelog +++ b/debian/changelog @@ -13,9 +13,9 @@ ikiwiki (3.14159266) UNRELEASED; urgency=low * Added support framework for multiple types of dependencies. * Allow declaring that a dependency does not encompass the content of a page. (By passing content => 0 to add_depends.) - * pagecount, calendar: Use a contentless dependency, which makes these - directives much less expensive to use, since page edits will - no longer trigger an unnecessary update. + * pagecount, calendar, postsparkline, progress: Use a contentless dependency, + which makes these directives much less expensive to use, since page + edits will no longer trigger an unnecessary update. * map: Use a contentless dependency unless show= is specified. This makes simple maps efficient enough that they can be used on sidebars! * inline: Use a contentless dependency in quick mode. -- cgit v1.2.3 From a8af271e5aed1c4aef3f66cee0847d609aedc705 Mon Sep 17 00:00:00 2001 From: Joey Hess Date: Sun, 4 Oct 2009 16:28:14 -0400 Subject: document effect of contentless dependencies on sidebar efficiency --- doc/plugins/sidebar.mdwn | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/doc/plugins/sidebar.mdwn b/doc/plugins/sidebar.mdwn index 36982eff3..4e356d65a 100644 --- a/doc/plugins/sidebar.mdwn +++ b/doc/plugins/sidebar.mdwn @@ -16,6 +16,10 @@ will turn off the sidebar altogether. Warning: Any change to the sidebar will cause a rebuild of the whole wiki, since every page includes a copy that has to be updated. This can -especially be a problem if the sidebar includes [[inline]] or [[map]] -directives, since any changes to pages inlined or mapped onto the sidebar +especially be a problem if the sidebar includes an [[ikiwiki/directive/inline]] +directive, since any changes to pages inlined into the sidebar will change the sidebar and cause a full wiki rebuild. + +Instead, if you include a [[ikiwiki/directive/map]] directive on the sidebar, +and it does not use the `show` parameter, only adding or removing pages +included in the map will cause a full rebuild. Modifying pages will not. -- cgit v1.2.3 From b4c8cc90726cb953898b14f378881bddd224a22c Mon Sep 17 00:00:00 2001 From: Joey Hess Date: Sun, 4 Oct 2009 17:38:10 -0400 Subject: update --- debian/changelog | 1 + 1 file changed, 1 insertion(+) diff --git a/debian/changelog b/debian/changelog index 0e9bf512b..21641434b 100644 --- a/debian/changelog +++ b/debian/changelog @@ -19,6 +19,7 @@ ikiwiki (3.14159266) UNRELEASED; urgency=low * map: Use a contentless dependency unless show= is specified. This makes simple maps efficient enough that they can be used on sidebars! * inline: Use a contentless dependency in quick mode. + * Transitive dependencies are now correctly supported. -- Joey Hess Sun, 27 Sep 2009 17:40:03 -0400 -- cgit v1.2.3 From be032a7b87d1080f1a54327346cb5b40432a056c Mon Sep 17 00:00:00 2001 From: Joey Hess Date: Sun, 4 Oct 2009 20:30:21 -0400 Subject: rework dependency types code Simplify, change default content depends number to 1, change interface to make more sense. --- IkiWiki.pm | 35 +++++++++++++++-------------------- IkiWiki/Plugin/calendar.pm | 18 +++++++++--------- IkiWiki/Plugin/edittemplate.pm | 2 +- IkiWiki/Plugin/listdirectives.pm | 2 +- IkiWiki/Plugin/meta.pm | 2 +- IkiWiki/Plugin/pagecount.pm | 4 ++-- IkiWiki/Plugin/postsparkline.pm | 2 +- IkiWiki/Plugin/progress.pm | 4 ++-- IkiWiki/Render.pm | 28 +++++++++++++--------------- doc/plugins/write.mdwn | 15 +++++++++------ ikiwiki-transition | 2 +- 11 files changed, 55 insertions(+), 59 deletions(-) diff --git a/IkiWiki.pm b/IkiWiki.pm index 5e5dc739d..c1d07531e 100644 --- a/IkiWiki.pm +++ b/IkiWiki.pm @@ -29,8 +29,8 @@ our $version='unknown'; # VERSION_AUTOREPLACE done by Makefile, DNE our $installdir='/usr'; # INSTALLDIR_AUTOREPLACE done by Makefile, DNE # Page dependency types. -our $DEPEND_EXISTS=1; -our $DEPEND_CONTENT=2; +our $DEPEND_CONTENT=1; +our $DEPEND_PRESENCE=2; # Optimisation. use Memoize; @@ -1540,13 +1540,13 @@ sub loadindex () { if (exists $d->{dependslist}) { # old format $depends{$page}={ - map { $_ => $DEPEND_CONTENT | $DEPEND_EXISTS } + map { $_ => $DEPEND_CONTENT } @{$d->{dependslist}} }; } elsif (exists $d->{depends} && ! ref $d->{depends}) { # old format - $depends{$page}={$d->{depends} => $DEPEND_CONTENT | $DEPEND_EXISTS}; + $depends{$page}={$d->{depends} => $DEPEND_CONTENT }; } elsif (exists $d->{depends}) { $depends{$page}=$d->{depends}; @@ -1771,16 +1771,23 @@ sub add_depends ($$;@) { my $page=shift; my $pagespec=shift; + # Is the pagespec a simple page name? my $simple=$pagespec =~ /$config{wiki_file_regexp}/ && $pagespec !~ /[\s*?()!]/; - my $deptype=$DEPEND_CONTENT | $DEPEND_EXISTS; + my $deptype=$DEPEND_CONTENT; if (@_) { my %params=@_; - if (defined $params{content} && $params{content} == 0 && - ($simple || pagespec_contentless($pagespec))) { - $deptype=$deptype & ~$DEPEND_CONTENT; + + # Is the pagespec limited to terms that will continue + # to match pages as long as those pages exist? + my $limited=1; + while ($limited && $pagespec=~m/(\w+)\([^\)]*\)/g) { + $limited = $1 =~ /^(glob|internal|creation_month|creation_day|creation_year|created_before|created_after)$/; } + + $deptype=$deptype & ~$DEPEND_CONTENT & $DEPEND_PRESENCE + if $params{presence} && $limited; } if ($simple) { @@ -1976,18 +1983,6 @@ sub pagespec_valid ($) { return ! $@; } -sub pagespec_contentless ($) { - my $spec=shift; - - while ($spec=~m{ - (\w+)\([^\)]*\) # only match pagespec functions - }igx) { - return 0 unless $1=~/^(glob|internal|creation_month|creation_day|creation_year|created_before|created_after)$/; - } - - return 1; -} - sub glob2re ($) { my $re=quotemeta(shift); $re=~s/\\\*/.*/g; diff --git a/IkiWiki/Plugin/calendar.pm b/IkiWiki/Plugin/calendar.pm index a5cc20882..a1117992a 100644 --- a/IkiWiki/Plugin/calendar.pm +++ b/IkiWiki/Plugin/calendar.pm @@ -105,21 +105,21 @@ sub format_month (@) { linktext => " $monthname "); } add_depends($params{page}, "$archivebase/$year/".sprintf("%02d", $month), - content => 0); + presence => 1); if (exists $cache{$pagespec}{"$pyear/$pmonth"}) { $purl = htmllink($params{page}, $params{destpage}, "$archivebase/$pyear/" . sprintf("%02d", $pmonth), linktext => " $pmonthname "); } add_depends($params{page}, "$archivebase/$pyear/".sprintf("%02d", $pmonth), - content => 0); + presence => 1); if (exists $cache{$pagespec}{"$nyear/$nmonth"}) { $nurl = htmllink($params{page}, $params{destpage}, "$archivebase/$nyear/" . sprintf("%02d", $nmonth), linktext => " $nmonthname "); } add_depends($params{page}, "$archivebase/$nyear/".sprintf("%02d", $nmonth), - content => 0); + presence => 1); # Start producing the month calendar $calendar=< 0); + add_depends($params{page}, $params{pages}, presence => 1); # Explicitly add all currently linked pages as dependencies, so # that if they are removed, the calendar will be sure to be updated. foreach my $p (@list) { - add_depends($params{page}, $p, content => 0); + add_depends($params{page}, $p, presence => 1); } return $calendar; @@ -249,19 +249,19 @@ sub format_year (@) { "$archivebase/$year", linktext => "$year"); } - add_depends($params{page}, "$archivebase/$year", content => 0); + add_depends($params{page}, "$archivebase/$year", presence => 1); if (exists $cache{$pagespec}{"$pyear"}) { $purl = htmllink($params{page}, $params{destpage}, "$archivebase/$pyear", linktext => "\←"); } - add_depends($params{page}, "$archivebase/$pyear", content => 0); + add_depends($params{page}, "$archivebase/$pyear", presence => 1); if (exists $cache{$pagespec}{"$nyear"}) { $nurl = htmllink($params{page}, $params{destpage}, "$archivebase/$nyear", linktext => "\→"); } - add_depends($params{page}, "$archivebase/$nyear", content => 0); + add_depends($params{page}, "$archivebase/$nyear", presence => 1); # Start producing the year calendar $calendar=<$monthabbr\n}; } - add_depends($params{page}, "$archivebase/$year/$mtag", content => 0); + add_depends($params{page}, "$archivebase/$year/$mtag", presence => 1); $calendar.=qq{\t\n} if ($month % $params{months_per_row} == 0); } diff --git a/IkiWiki/Plugin/edittemplate.pm b/IkiWiki/Plugin/edittemplate.pm index 89d450725..2dd1dbe68 100644 --- a/IkiWiki/Plugin/edittemplate.pm +++ b/IkiWiki/Plugin/edittemplate.pm @@ -58,7 +58,7 @@ sub preprocess (@) { $pagestate{$params{page}}{edittemplate}{$params{match}}=$link; return "" if ($params{silent} && IkiWiki::yesno($params{silent})); - add_depends($params{page}, $link, content => 0); + add_depends($params{page}, $link, presence => 1); return sprintf(gettext("edittemplate %s registered for %s"), htmllink($params{page}, $params{destpage}, $link), $params{match}); diff --git a/IkiWiki/Plugin/listdirectives.pm b/IkiWiki/Plugin/listdirectives.pm index 96150f986..4023ed7d7 100644 --- a/IkiWiki/Plugin/listdirectives.pm +++ b/IkiWiki/Plugin/listdirectives.pm @@ -84,7 +84,7 @@ sub preprocess (@) { foreach my $plugin (@pluginlist) { $result .= '
  • '; my $link=linkpage($config{directive_description_dir}."/".$plugin); - add_depends($params{page}, $link, content => 0); + add_depends($params{page}, $link, presence => 1); $result .= htmllink($params{page}, $params{destpage}, $link); $result .= '
  • '; } diff --git a/IkiWiki/Plugin/meta.pm b/IkiWiki/Plugin/meta.pm index eef3013a0..9b041a748 100644 --- a/IkiWiki/Plugin/meta.pm +++ b/IkiWiki/Plugin/meta.pm @@ -195,7 +195,7 @@ sub preprocess (@) { if (! length $link) { error gettext("redir page not found") } - add_depends($page, $link, content => 0); + add_depends($page, $link, presence => 1); $value=urlto($link, $page); $value.='#'.$redir_anchor if defined $redir_anchor; diff --git a/IkiWiki/Plugin/pagecount.pm b/IkiWiki/Plugin/pagecount.pm index 17eda0618..80561350b 100644 --- a/IkiWiki/Plugin/pagecount.pm +++ b/IkiWiki/Plugin/pagecount.pm @@ -23,8 +23,8 @@ sub preprocess (@) { $params{pages}="*" unless defined $params{pages}; # Needs to update count whenever a page is added or removed, so - # register a contentless dependency. - add_depends($params{page}, $params{pages}, content => 0); + # register a presence dependency. + add_depends($params{page}, $params{pages}, presence => 1); my @pages; if ($params{pages} eq "*") { diff --git a/IkiWiki/Plugin/postsparkline.pm b/IkiWiki/Plugin/postsparkline.pm index 694d39575..3205958d4 100644 --- a/IkiWiki/Plugin/postsparkline.pm +++ b/IkiWiki/Plugin/postsparkline.pm @@ -48,7 +48,7 @@ sub preprocess (@) { error gettext("unknown formula"); } - add_depends($params{page}, $params{pages}, content => 0); + add_depends($params{page}, $params{pages}, presence => 1); my @list=sort { $params{timehash}->{$b} <=> $params{timehash}->{$a} } pagespec_match_list( diff --git a/IkiWiki/Plugin/progress.pm b/IkiWiki/Plugin/progress.pm index 3b664f4cb..26c537a84 100644 --- a/IkiWiki/Plugin/progress.pm +++ b/IkiWiki/Plugin/progress.pm @@ -36,8 +36,8 @@ sub preprocess (@) { $fill.="%"; } elsif (defined $params{totalpages} and defined $params{donepages}) { - add_depends($params{page}, $params{totalpages}, content => 0); - add_depends($params{page}, $params{donepages}, content => 0); + add_depends($params{page}, $params{totalpages}, presence => 1); + add_depends($params{page}, $params{donepages}, presence => 1); my @pages=keys %pagesources; my $totalcount=0; diff --git a/IkiWiki/Render.pm b/IkiWiki/Render.pm index 3fc750925..cf0c3fe08 100644 --- a/IkiWiki/Render.pm +++ b/IkiWiki/Render.pm @@ -473,13 +473,11 @@ sub refresh () { if (exists $depends_simple{$p}) { foreach my $d (keys %{$depends_simple{$p}}) { - if ($depends_simple{$p}{$d} == $IkiWiki::DEPEND_EXISTS) { - if (exists $lc_exists_changed{$d}) { - $reason = $d; - last; - } - } - elsif (exists $lc_changed{$d}) { + if (($depends_simple{$p}{$d} & $IkiWiki::DEPEND_CONTENT && + exists $lc_changed{$d}) + || + ($depends_simple{$p}{$d} & $IkiWiki::DEPEND_PRESENCE && + exists $lc_exists_changed{$d})) { $reason = $d; last; } @@ -492,22 +490,22 @@ sub refresh () { next if $@ || ! defined $sub; my @candidates; - if ($depends{$p}{$d} == $IkiWiki::DEPEND_EXISTS) { - @candidates=@exists_changed; - } - else { + if ($depends_simple{$p}{$d} & $IkiWiki::DEPEND_CONTENT) { @candidates=@changed; } + elsif ($depends{$p}{$d} & $IkiWiki::DEPEND_PRESENCE) { + @candidates=@exists_changed; + } # only consider internal files # if the page explicitly depends # on such files if ($d =~ /internal\(/) { - if ($depends{$p}{$d} == $IkiWiki::DEPEND_EXISTS) { - push @candidates, @internal; - } - else { + if ($depends_simple{$p}{$d} & $IkiWiki::DEPEND_CONTENT) { push @candidates, @internal, @internal_change; } + elsif ($depends{$p}{$d} & $IkiWiki::DEPEND_PRESENCE) { + push @candidates, @internal; + } } foreach my $file (@candidates) { diff --git a/doc/plugins/write.mdwn b/doc/plugins/write.mdwn index c244c1f2f..73db6f12a 100644 --- a/doc/plugins/write.mdwn +++ b/doc/plugins/write.mdwn @@ -613,12 +613,15 @@ generating a link to a page. Makes the specified page depend on the specified [[ikiwiki/PageSpec]]. -Additional named parameters can be passed, to indicate what type of -dependency this is. - -Currently, only a "content" parameter is specified. If set to 0, the -dependency does not involve the content of pages matching the PageSpec, but -only their existence. +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 in the text of links on a matching page + triggers the dependency #### `pagespec_match($$;@)` diff --git a/ikiwiki-transition b/ikiwiki-transition index c50a748e8..1bebb1176 100755 --- a/ikiwiki-transition +++ b/ikiwiki-transition @@ -299,7 +299,7 @@ sub oldloadindex { $pagemtime{$page}=$items{mtime}[0]; $oldlinks{$page}=[@{$items{link}}]; $links{$page}=[@{$items{link}}]; - $depends{$page}={ $items{depends}[0] => $IkiWiki::DEPEND_CONTENT | $IkiWiki::DEPEND_EXISTS } if exists $items{depends}; + $depends{$page}={ $items{depends}[0] => $IkiWiki::DEPEND_CONTENT } if exists $items{depends}; $destsources{$_}=$page foreach @{$items{dest}}; $renderedfiles{$page}=[@{$items{dest}}]; $pagecase{lc $page}=$page; -- cgit v1.2.3 From d0f116478cdd8841c7905f2629bb679f7f36a5a4 Mon Sep 17 00:00:00 2001 From: Joey Hess Date: Sun, 4 Oct 2009 20:34:43 -0400 Subject: update --- debian/changelog | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/debian/changelog b/debian/changelog index 21641434b..7ca0d9e42 100644 --- a/debian/changelog +++ b/debian/changelog @@ -11,14 +11,14 @@ ikiwiki (3.14159266) UNRELEASED; urgency=low * Fix a bug that could lead to duplicate links being recorded for tags. * Added support framework for multiple types of dependencies. - * Allow declaring that a dependency does not encompass the content of a - page. (By passing content => 0 to add_depends.) - * pagecount, calendar, postsparkline, progress: Use a contentless dependency, + * Allow declaring that a dependency is only affected by page presence. + (By passing presence => 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. - * map: Use a contentless dependency unless show= is specified. - This makes simple maps efficient enough that they can be used on sidebars! - * inline: Use a contentless dependency in quick mode. + * map: Use a presence dependency unless show= is specified. + This makes maps efficient enough that they can be used on sidebars! + * inline: Use a presence dependency in quick mode. * Transitive dependencies are now correctly supported. -- Joey Hess Sun, 27 Sep 2009 17:40:03 -0400 -- cgit v1.2.3 From 36c605cadace789d14354a1c835457f5f23ee1c2 Mon Sep 17 00:00:00 2001 From: Joey Hess Date: Sun, 4 Oct 2009 23:27:00 -0400 Subject: add test suite for add_depends and found a bug in my bitmath.. --- IkiWiki.pm | 2 +- t/add_depends.t | 68 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 69 insertions(+), 1 deletion(-) create mode 100644 t/add_depends.t diff --git a/IkiWiki.pm b/IkiWiki.pm index 9591a8160..0bb0c1746 100644 --- a/IkiWiki.pm +++ b/IkiWiki.pm @@ -1786,7 +1786,7 @@ sub add_depends ($$;@) { $limited = $1 =~ /^(glob|internal|creation_month|creation_day|creation_year|created_before|created_after)$/; } - $deptype=$deptype & ~$DEPEND_CONTENT & $DEPEND_PRESENCE + $deptype=$deptype & ~$DEPEND_CONTENT | $DEPEND_PRESENCE if $params{presence} && $limited; } diff --git a/t/add_depends.t b/t/add_depends.t new file mode 100644 index 000000000..935a57944 --- /dev/null +++ b/t/add_depends.t @@ -0,0 +1,68 @@ +#!/usr/bin/perl +use warnings; +use strict; +use Test::More tests => 50; + +BEGIN { use_ok("IkiWiki"); } +%config=IkiWiki::defaultconfig(); +$config{srcdir}=$config{destdir}="/dev/null"; +IkiWiki::checkconfig(); + +# avoids adding an unparseable pagespec +ok(! add_depends("foo", "foo and (bar")); +ok(! add_depends("foo", "foo another")); + +# simple and not-so-simple dependencies split +ok(add_depends("foo", "*")); +ok(add_depends("foo", "bar")); +ok(add_depends("foo", "BAZ")); +ok(exists $IkiWiki::depends_simple{foo}{"bar"}); +ok(exists $IkiWiki::depends_simple{foo}{"baz"}); # lowercase +ok(! exists $IkiWiki::depends_simple{foo}{"*"}); +ok(! exists $IkiWiki::depends{foo}{"bar"}); +ok(! exists $IkiWiki::depends{foo}{"baz"}); + +# default dependencies are content dependencies +ok($IkiWiki::depends{foo}{"*"} & $IkiWiki::DEPEND_CONTENT); +ok(! ($IkiWiki::depends{foo}{"*"} & ($IkiWiki::DEPEND_PRESENCE | $IkiWiki::DEPEND_LINKS))); +ok($IkiWiki::depends_simple{foo}{"bar"} & $IkiWiki::DEPEND_CONTENT); +ok(! ($IkiWiki::depends_simple{foo}{"bar"} & ($IkiWiki::DEPEND_PRESENCE | $IkiWiki::DEPEND_LINKS))); + +# adding other dep types standalone +ok(add_depends("foo2", "*", presence => 1)); +ok(add_depends("foo2", "bar", links => 1)); +ok($IkiWiki::depends{foo2}{"*"} & $IkiWiki::DEPEND_PRESENCE); +ok(! ($IkiWiki::depends{foo2}{"*"} & ($IkiWiki::DEPEND_CONTENT | $IkiWiki::DEPEND_LINKS))); +ok($IkiWiki::depends_simple{foo2}{"bar"} & $IkiWiki::DEPEND_LINKS); +ok(! ($IkiWiki::depends_simple{foo2}{"bar"} & ($IkiWiki::DEPEND_PRESENCE | $IkiWiki::DEPEND_CONTENT))); + +# adding combined dep types +ok(add_depends("foo2", "baz", links => 1, presence => 1)); +ok($IkiWiki::depends_simple{foo2}{"baz"} & $IkiWiki::DEPEND_LINKS); +ok($IkiWiki::depends_simple{foo2}{"baz"} & $IkiWiki::DEPEND_PRESENCE); +ok(! ($IkiWiki::depends_simple{foo2}{"baz"} & $IkiWiki::DEPEND_CONTENT)); + +# adding a pagespec that requires page metadata should cause a fallback to +# a content dependency +foreach my $spec ("* and ! link(bar)", "* or link(bar)", "unknownspec()", + "title(hi)", + "* or backlink(yo)", # this one could actually be acceptably be + # detected to not need a content dep .. in + # theory! + ) { + ok(add_depends("foo3", $spec, presence => 1)); + ok($IkiWiki::depends{foo3}{$spec} & $IkiWiki::DEPEND_CONTENT); + ok(! ($IkiWiki::depends{foo3}{$spec} & ($IkiWiki::DEPEND_PRESENCE | $IkiWiki::DEPEND_LINKS))); +} + +# adding dep types to existing dependencies should merge the flags +ok(add_depends("foo2", "baz")); +ok($IkiWiki::depends_simple{foo2}{"baz"} & $IkiWiki::DEPEND_LINKS); +ok($IkiWiki::depends_simple{foo2}{"baz"} & $IkiWiki::DEPEND_PRESENCE); +ok(($IkiWiki::depends_simple{foo2}{"baz"} & $IkiWiki::DEPEND_CONTENT)); +ok(add_depends("foo2", "bar", presence => 1)); # had only links before +ok($IkiWiki::depends_simple{foo2}{"bar"} & ($IkiWiki::DEPEND_LINKS | $IkiWiki::DEPEND_PRESENCE)); +ok(! ($IkiWiki::depends_simple{foo2}{"bar"} & $IkiWiki::DEPEND_CONTENT)); +ok(add_depends("foo", "bar", links => 1)); # had only content before +ok($IkiWiki::depends{foo}{"*"} & ($IkiWiki::DEPEND_CONTENT | $IkiWiki::DEPEND_LINKS)); +ok(! ($IkiWiki::depends{foo}{"*"} & $IkiWiki::DEPEND_PRESENCE)); -- cgit v1.2.3 From 89b65695e778699742bcf93b0ab0304fd53e30ca Mon Sep 17 00:00:00 2001 From: Joey Hess Date: Mon, 5 Oct 2009 13:40:35 -0400 Subject: typos --- IkiWiki/Render.pm | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/IkiWiki/Render.pm b/IkiWiki/Render.pm index cf0c3fe08..324ef24fa 100644 --- a/IkiWiki/Render.pm +++ b/IkiWiki/Render.pm @@ -490,7 +490,7 @@ sub refresh () { next if $@ || ! defined $sub; my @candidates; - if ($depends_simple{$p}{$d} & $IkiWiki::DEPEND_CONTENT) { + if ($depends{$p}{$d} & $IkiWiki::DEPEND_CONTENT) { @candidates=@changed; } elsif ($depends{$p}{$d} & $IkiWiki::DEPEND_PRESENCE) { @@ -500,7 +500,7 @@ sub refresh () { # if the page explicitly depends # on such files if ($d =~ /internal\(/) { - if ($depends_simple{$p}{$d} & $IkiWiki::DEPEND_CONTENT) { + if ($depends{$p}{$d} & $IkiWiki::DEPEND_CONTENT) { push @candidates, @internal, @internal_change; } elsif ($depends{$p}{$d} & $IkiWiki::DEPEND_PRESENCE) { -- cgit v1.2.3 From 666a9613a12e3b3d36cdd1e818c44f1890f05b0d Mon Sep 17 00:00:00 2001 From: Joey Hess Date: Mon, 5 Oct 2009 14:08:46 -0400 Subject: implement links dependencies Involved some code refactoring so that same code that detects link changes for backlinks updating can be used for link dependency checking. The nice thing is that link dep checking is thus comopletly free! --- IkiWiki.pm | 3 ++ IkiWiki/Render.pm | 111 ++++++++++++++++++++++++++++++------------------------ 2 files changed, 65 insertions(+), 49 deletions(-) diff --git a/IkiWiki.pm b/IkiWiki.pm index 0bb0c1746..b895e12fc 100644 --- a/IkiWiki.pm +++ b/IkiWiki.pm @@ -31,6 +31,7 @@ our $installdir='/usr'; # INSTALLDIR_AUTOREPLACE done by Makefile, DNE # Page dependency types. our $DEPEND_CONTENT=1; our $DEPEND_PRESENCE=2; +our $DEPEND_LINKS=4; # Optimisation. use Memoize; @@ -1788,6 +1789,8 @@ sub add_depends ($$;@) { $deptype=$deptype & ~$DEPEND_CONTENT | $DEPEND_PRESENCE if $params{presence} && $limited; + $deptype=$deptype & ~$DEPEND_CONTENT | $DEPEND_LINKS + if $params{links} && $limited; } if ($simple) { diff --git a/IkiWiki/Render.pm b/IkiWiki/Render.pm index 324ef24fa..4e8aae3bc 100644 --- a/IkiWiki/Render.pm +++ b/IkiWiki/Render.pm @@ -58,6 +58,37 @@ sub backlinks ($) { return @links; } +sub find_changed_links (@_) { + my %linkchanged; + my %linkchangers; + foreach my $file (@_) { + my $page=pagename($file); + + if (exists $links{$page}) { + foreach my $link (map { bestlink($page, $_) } @{$links{$page}}) { + if (length $link && + (! exists $oldlinks{$page} || + ! grep { bestlink($page, $_) eq $link } @{$oldlinks{$page}})) { + $linkchanged{$link}=1; + $linkchangers{lc($page)}=1; + } + } + } + if (exists $oldlinks{$page}) { + foreach my $link (map { bestlink($page, $_) } @{$oldlinks{$page}}) { + if (length $link && + (! exists $links{$page} || + ! grep { bestlink($page, $_) eq $link } @{$links{$page}})) { + $linkchanged{$link}=1; + $linkchangers{lc($page)}=1; + } + } + } + } + + return \%linkchanged, \%linkchangers; +} + sub genpage ($$) { my $page=shift; my $content=shift; @@ -455,10 +486,12 @@ sub refresh () { } if (%rendered || @del || @internal || @internal_change) { - my @changed; - my $changes; + my @changed=(keys %rendered, @del); + my ($linkchanged, $linkchangers)=find_changed_links(@changed); + + my $unsettled; do { - $changes=0; + $unsettled=0; @changed=(keys %rendered, @del); my @exists_changed=(@add, @del); @@ -474,10 +507,14 @@ sub refresh () { if (exists $depends_simple{$p}) { foreach my $d (keys %{$depends_simple{$p}}) { if (($depends_simple{$p}{$d} & $IkiWiki::DEPEND_CONTENT && - exists $lc_changed{$d}) + $lc_changed{$d}) || ($depends_simple{$p}{$d} & $IkiWiki::DEPEND_PRESENCE && - exists $lc_exists_changed{$d})) { + $lc_exists_changed{$d}) + || + ($depends_simple{$p}{$d} & $IkiWiki::DEPEND_LINKS && + $linkchangers->{$d}) + ) { $reason = $d; last; } @@ -489,29 +526,30 @@ sub refresh () { my $sub=pagespec_translate($d); next if $@ || ! defined $sub; - my @candidates; - if ($depends{$p}{$d} & $IkiWiki::DEPEND_CONTENT) { - @candidates=@changed; - } - elsif ($depends{$p}{$d} & $IkiWiki::DEPEND_PRESENCE) { - @candidates=@exists_changed; - } # only consider internal files # if the page explicitly depends # on such files - if ($d =~ /internal\(/) { - if ($depends{$p}{$d} & $IkiWiki::DEPEND_CONTENT) { - push @candidates, @internal, @internal_change; - } - elsif ($depends{$p}{$d} & $IkiWiki::DEPEND_PRESENCE) { - push @candidates, @internal; - } + my $internal_dep=$d =~ /internal\(/; + + my @candidates; + if ($depends{$p}{$d} & $IkiWiki::DEPEND_PRESENCE) { + @candidates=@exists_changed; + push @candidates, @internal + if $internal_dep; } - + if (($depends{$p}{$d} & ($IkiWiki::DEPEND_CONTENT | $IkiWiki::DEPEND_LINKS))) { + @candidates=@changed; + push @candidates, @internal, @internal_change + if $internal_dep; + } + foreach my $file (@candidates) { next if $file eq $f; my $page=pagename($file); if ($sub->($page, location => $p)) { + if ($depends{$p}{$d} & $IkiWiki::DEPEND_LINKS) { + next unless $linkchangers->{lc($page)}; + } $reason = $page; last D; } @@ -523,39 +561,14 @@ sub refresh () { debug(sprintf(gettext("building %s, which depends on %s"), $f, $reason)); render($f); $rendered{$f}=1; - $changes++; + $unsettled=1; last; } } - } while $changes; + } while $unsettled; - # handle backlinks; if a page has added/removed links, - # update the pages it links to - my %linkchanged; - foreach my $file (@changed) { - my $page=pagename($file); - - if (exists $links{$page}) { - foreach my $link (map { bestlink($page, $_) } @{$links{$page}}) { - if (length $link && - (! exists $oldlinks{$page} || - ! grep { bestlink($page, $_) eq $link } @{$oldlinks{$page}})) { - $linkchanged{$link}=1; - } - } - } - if (exists $oldlinks{$page}) { - foreach my $link (map { bestlink($page, $_) } @{$oldlinks{$page}}) { - if (length $link && - (! exists $links{$page} || - ! grep { bestlink($page, $_) eq $link } @{$links{$page}})) { - $linkchanged{$link}=1; - } - } - } - } - - foreach my $link (keys %linkchanged) { + # update backlinks at end + foreach my $link (keys %{$linkchanged}) { my $linkfile=$pagesources{$link}; if (defined $linkfile) { next if $rendered{$linkfile}; -- cgit v1.2.3 From e96992bbc8fc37040eda5119c475ff4174c43339 Mon Sep 17 00:00:00 2001 From: Joey Hess Date: Mon, 5 Oct 2009 14:33:42 -0400 Subject: fix add_depends to new api --- IkiWiki/Plugin/inline.pm | 4 ++-- IkiWiki/Plugin/map.pm | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/IkiWiki/Plugin/inline.pm b/IkiWiki/Plugin/inline.pm index 5133c4ba6..cebd9037c 100644 --- a/IkiWiki/Plugin/inline.pm +++ b/IkiWiki/Plugin/inline.pm @@ -197,7 +197,7 @@ sub preprocess_inline (@) { split ' ', $params{pagenames}; } else { - add_depends($params{page}, $params{pages}, content => ! $quick); + add_depends($params{page}, $params{pages}, presence => $quick); @list = pagespec_match_list( [ grep { $_ ne $params{page} } keys %pagesources ], @@ -250,7 +250,7 @@ sub preprocess_inline (@) { # Explicitly add all currently displayed pages as dependencies, so # that if they are removed, the inline will be sure to be updated. foreach my $p ($#list >= $#feedlist ? @list : @feedlist) { - add_depends($params{page}, $p, content => ! $quick); + add_depends($params{page}, $p, presence => $quick); } if ($feeds && exists $params{feedpages}) { diff --git a/IkiWiki/Plugin/map.pm b/IkiWiki/Plugin/map.pm index 682960777..625cfdfca 100644 --- a/IkiWiki/Plugin/map.pm +++ b/IkiWiki/Plugin/map.pm @@ -70,11 +70,11 @@ sub preprocess (@) { # Needs to update whenever a page is added or removed (or in some # cases, when its content changes, if show= is specified), so # register a dependency. - add_depends($params{page}, $params{pages}, content => exists $params{show}); + add_depends($params{page}, $params{pages}, presence => ! exists $params{show}); # Explicitly add all currently shown pages, to detect when pages # are removed. foreach my $item (keys %mapitems) { - add_depends($params{page}, $item, content => exists $params{show}); + add_depends($params{page}, $item, presence => ! exists $params{show}); } # Create the map. -- cgit v1.2.3 From c6bf4228d5c988e715ff08a9374b72ce054daa2c Mon Sep 17 00:00:00 2001 From: Joey Hess Date: Mon, 5 Oct 2009 15:01:05 -0400 Subject: make links dependencies fire if broken links change --- IkiWiki/Render.pm | 41 ++++++++++++++++++++++++++++------------- doc/plugins/write.mdwn | 6 ++++-- 2 files changed, 32 insertions(+), 15 deletions(-) diff --git a/IkiWiki/Render.pm b/IkiWiki/Render.pm index 4e8aae3bc..599bb26e2 100644 --- a/IkiWiki/Render.pm +++ b/IkiWiki/Render.pm @@ -63,24 +63,39 @@ sub find_changed_links (@_) { my %linkchangers; foreach my $file (@_) { my $page=pagename($file); - + if (exists $links{$page}) { - foreach my $link (map { bestlink($page, $_) } @{$links{$page}}) { - if (length $link && - (! exists $oldlinks{$page} || - ! grep { bestlink($page, $_) eq $link } @{$oldlinks{$page}})) { - $linkchanged{$link}=1; - $linkchangers{lc($page)}=1; + foreach my $l (@{$links{$page}}) { + my $link=bestlink($page, $l); + if (length $link) { + if (! exists $oldlinks{$page} || + ! grep { bestlink($page, $_) eq $link } @{$oldlinks{$page}}) { + $linkchanged{$link}=1; + $linkchangers{lc($page)}=1; + } + } + else { + if (! grep { lc $_ eq lc $l } @{$oldlinks{$page}}) { + $linkchangers{lc($page)}=1 + } } + } } if (exists $oldlinks{$page}) { - foreach my $link (map { bestlink($page, $_) } @{$oldlinks{$page}}) { - if (length $link && - (! exists $links{$page} || - ! grep { bestlink($page, $_) eq $link } @{$links{$page}})) { - $linkchanged{$link}=1; - $linkchangers{lc($page)}=1; + foreach my $l (@{$oldlinks{$page}}) { + my $link=bestlink($page, $l); + if (length $link) { + if (! exists $links{$page} || + ! grep { bestlink($page, $_) eq $link } @{$links{$page}}) { + $linkchanged{$link}=1; + $linkchangers{lc($page)}=1; + } + } + else { + if (! grep { lc $_ eq lc $l } @{$links{$page}}) { + $linkchangers{lc($page)}=1 + } } } } diff --git a/doc/plugins/write.mdwn b/doc/plugins/write.mdwn index 73db6f12a..133030f08 100644 --- a/doc/plugins/write.mdwn +++ b/doc/plugins/write.mdwn @@ -620,8 +620,10 @@ 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 in the text of links on 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. #### `pagespec_match($$;@)` -- cgit v1.2.3 From 846026b20be2ab177eb58d3add468419625c3cc1 Mon Sep 17 00:00:00 2001 From: Joey Hess Date: Mon, 5 Oct 2009 15:08:57 -0400 Subject: update --- debian/changelog | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/debian/changelog b/debian/changelog index 7ca0d9e42..0255ac5d0 100644 --- a/debian/changelog +++ b/debian/changelog @@ -11,14 +11,17 @@ ikiwiki (3.14159266) UNRELEASED; urgency=low * Fix a bug that could lead to duplicate links being recorded for tags. * Added support framework for multiple types of dependencies. - * Allow declaring that a dependency is only affected by page presence. - (By passing presence => 1 to add_depends.) + * 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. * map: Use a presence dependency unless show= is specified. This makes maps efficient enough that they can be used on sidebars! * inline: Use a presence dependency in quick mode. + * brokenlinks: Use a link dependency. + This makes it much more efficient, only updating when really necessary. * Transitive dependencies are now correctly supported. -- Joey Hess Sun, 27 Sep 2009 17:40:03 -0400 -- cgit v1.2.3 From f41caf57eabdaa2345eba1718450af686dca3971 Mon Sep 17 00:00:00 2001 From: Joey Hess Date: Mon, 5 Oct 2009 15:09:09 -0400 Subject: use links dependency --- IkiWiki/Plugin/brokenlinks.pm | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/IkiWiki/Plugin/brokenlinks.pm b/IkiWiki/Plugin/brokenlinks.pm index b8ed2b8de..9e65f52c6 100644 --- a/IkiWiki/Plugin/brokenlinks.pm +++ b/IkiWiki/Plugin/brokenlinks.pm @@ -23,9 +23,8 @@ sub preprocess (@) { my %params=@_; $params{pages}="*" unless defined $params{pages}; - # Needs to update whenever a page is changed, - # added or removed, in order to see the link changes. - add_depends($params{page}, $params{pages}); + # Needs to update whenever the links on a page change. + add_depends($params{page}, $params{pages}, links => 1); my @broken; foreach my $link (keys %IkiWiki::brokenlinks) { -- cgit v1.2.3 From 7123178732674268a1dce09277536dcdc68825f5 Mon Sep 17 00:00:00 2001 From: Joey Hess Date: Mon, 5 Oct 2009 15:14:18 -0400 Subject: oprhans: Use a combination of precense and link dependencies. This makes it more efficient. It also fixes a longstanding bug, where if only a small set of pages were considered by orphans, changes to links on other pages failed to cause an update. --- IkiWiki/Plugin/orphans.pm | 10 +++++++--- debian/changelog | 4 ++++ 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/IkiWiki/Plugin/orphans.pm b/IkiWiki/Plugin/orphans.pm index d981670e7..ae330b23b 100644 --- a/IkiWiki/Plugin/orphans.pm +++ b/IkiWiki/Plugin/orphans.pm @@ -23,9 +23,13 @@ sub preprocess (@) { my %params=@_; $params{pages}="*" unless defined $params{pages}; - # Needs to update whenever a page is changed, added, or removed, - # in order to see the link changes. - add_depends($params{page}, $params{pages}); + # Needs to update whenever a link changes, on any page + # since any page could link to one of the pages we're + # considering as orphans. + add_depends($params{page}, "*", links => 1); + # Also needs to update whenever potential orphans are added or + # removed. + add_depends($params{page}, $params{pages}, presence => 1); my @orphans; foreach my $page (pagespec_match_list( diff --git a/debian/changelog b/debian/changelog index 0255ac5d0..363bb9dbd 100644 --- a/debian/changelog +++ b/debian/changelog @@ -22,6 +22,10 @@ ikiwiki (3.14159266) UNRELEASED; urgency=low * inline: Use a presence dependency in quick mode. * brokenlinks: Use a link dependency. This makes it much more efficient, only updating when really necessary. + * oprhans: Use a combination of precense and link dependencies. + This makes it more efficient. It also fixes a longstanding bug, + where if only a small set of pages were considered by orphans, + changes to links on other pages failed to cause an update. * Transitive dependencies are now correctly supported. -- Joey Hess Sun, 27 Sep 2009 17:40:03 -0400 -- cgit v1.2.3 From fc864515b857694da6752879edeb2f82fd12e3a4 Mon Sep 17 00:00:00 2001 From: Joey Hess Date: Mon, 5 Oct 2009 15:16:14 -0400 Subject: omit forum and javascript from list --- doc/plugins/orphans.mdwn | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/plugins/orphans.mdwn b/doc/plugins/orphans.mdwn index ea7c4df13..8c0d0b933 100644 --- a/doc/plugins/orphans.mdwn +++ b/doc/plugins/orphans.mdwn @@ -10,5 +10,6 @@ Here's a list of orphaned pages on this wiki: [[!orphans pages="* and !news/* and !todo/* and !bugs/* and !users/* and !recentchanges and !examples/* and !tips/* and !sandbox/* and !templates/* and +!forum/* and !*.js !wikiicons/* and !plugins/*"]] """]] -- cgit v1.2.3 From dc6fab3824c9848cdaf8b252253d690f96573d25 Mon Sep 17 00:00:00 2001 From: Joey Hess Date: Mon, 5 Oct 2009 15:17:36 -0400 Subject: syntax --- doc/plugins/orphans.mdwn | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/plugins/orphans.mdwn b/doc/plugins/orphans.mdwn index 8c0d0b933..e403c2d18 100644 --- a/doc/plugins/orphans.mdwn +++ b/doc/plugins/orphans.mdwn @@ -10,6 +10,6 @@ Here's a list of orphaned pages on this wiki: [[!orphans pages="* and !news/* and !todo/* and !bugs/* and !users/* and !recentchanges and !examples/* and !tips/* and !sandbox/* and !templates/* and -!forum/* and !*.js +!forum/* and !*.js and !wikiicons/* and !plugins/*"]] """]] -- cgit v1.2.3 From d6cdced589f31471622ed481f88e33e070388c27 Mon Sep 17 00:00:00 2001 From: Joey Hess Date: Mon, 5 Oct 2009 15:22:17 -0400 Subject: fix documentation of quick It *always* turns off feeds, because feeds require a look at all pages. --- doc/ikiwiki/directive/inline.mdwn | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/ikiwiki/directive/inline.mdwn b/doc/ikiwiki/directive/inline.mdwn index 99f795972..4e087ab6c 100644 --- a/doc/ikiwiki/directive/inline.mdwn +++ b/doc/ikiwiki/directive/inline.mdwn @@ -98,7 +98,7 @@ Here are some less often needed parameters: * `feedonly` - Only generate the feed, do not display the pages inline on the page. * `quick` - Build archives in quick mode, without reading page contents for - metadata. By default, this also turns off generation of any feeds. + metadata. This also turns off generation of any feeds. * `timeformat` - Use this to specify how to display the time or date for pages in the blog. The format string is passed to the strftime(3) function. * `feedpages` - A [[PageSpec]] of inlined pages to include in the rss/atom -- cgit v1.2.3 From f7d04d106721a6bff6dfd4a0a7aa162cd2ce5536 Mon Sep 17 00:00:00 2001 From: Joey Hess Date: Mon, 5 Oct 2009 15:26:15 -0400 Subject: switch plugins page to use a map instead of an inline A map just seems a better fit for reference, since it deliniates the contrib plugins better, and orders better. It also has the advantage of being less expensive, since the plugins page does not need to update when eg, the pagecount page changes. Only downside is, no rss feed of new plugins. Which I know a few people were subscribed to. --- doc/plugins.mdwn | 6 ++---- doc/plugins/contrib.mdwn | 4 +--- 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/doc/plugins.mdwn b/doc/plugins.mdwn index 527568208..bd7ee538b 100644 --- a/doc/plugins.mdwn +++ b/doc/plugins.mdwn @@ -13,7 +13,5 @@ will fit most uses of ikiwiki. ## Plugin directory -[[!inline pages="plugins/* and !plugins/type/* and !plugins/write and -!plugins/write/* and !plugins/contrib and !plugins/install and !*/Discussion" -feedpages="created_after(plugins/graphviz)" archive="yes" sort=title -rootpage="plugins/contrib" postformtext="Add a new plugin named:" show=0]] +[[!map pages="plugins/* and !plugins/type/* and !plugins/write and +!plugins/write/* and !plugins/contrib and !plugins/install and !*/Discussion"]] diff --git a/doc/plugins/contrib.mdwn b/doc/plugins/contrib.mdwn index a03e6a95d..ac6c1b751 100644 --- a/doc/plugins/contrib.mdwn +++ b/doc/plugins/contrib.mdwn @@ -1,6 +1,4 @@ These plugins are provided by third parties and are not currently included in ikiwiki. See [[install]] for installation help. -[[!inline pages="plugins/contrib/* and !*/Discussion" -feedpages="created_after(plugins/contrib/navbar)" archive="yes" -rootpage="plugins/contrib" postformtext="Add a new plugin named:" show=0]] +[[!map pages="plugins/contrib/* and !*/Discussion"]] -- cgit v1.2.3 From e7144e918f0d15a9bbb1a4842ff7300ce61a1886 Mon Sep 17 00:00:00 2001 From: Joey Hess Date: Mon, 5 Oct 2009 15:36:51 -0400 Subject: clarify amoung I found it really hard to understand from the old description.. --- doc/ikiwiki/directive/pagestats.mdwn | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/doc/ikiwiki/directive/pagestats.mdwn b/doc/ikiwiki/directive/pagestats.mdwn index 66f851dbd..f14c80b07 100644 --- a/doc/ikiwiki/directive/pagestats.mdwn +++ b/doc/ikiwiki/directive/pagestats.mdwn @@ -12,13 +12,13 @@ And here's how to create a table of all the pages on the wiki: \[[!pagestats style="table"]] -The optional `among` parameter limits display to pages that match a -[[ikiwiki/PageSpec]]. For instance, to display a cloud of tags used on blog -entries, you could use: +The optional `among` parameter limits the pages whose outgoing links are +considered. For instance, to display a cloud of tags used on blog +entries, while ignoring other pages that use those tags, you could use: \[[!pagestats pages="tags/*" among="blog/posts/*"]] -or to display a cloud of tags related to Linux, you could use: +Or to display a cloud of tags related to Linux, you could use: \[[!pagestats pages="tags/* and not tags/linux" among="tagged(linux)"]] -- cgit v1.2.3 From 61a36de432c58a8d7703b1ecc5d5704981e10e2d Mon Sep 17 00:00:00 2001 From: Joey Hess Date: Mon, 5 Oct 2009 15:40:18 -0400 Subject: closures --- doc/bugs/transitive_dependencies.mdwn | 2 +- doc/todo/dependency_types.mdwn | 9 ++++----- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/doc/bugs/transitive_dependencies.mdwn b/doc/bugs/transitive_dependencies.mdwn index 9586bc9b0..0a2e9ec28 100644 --- a/doc/bugs/transitive_dependencies.mdwn +++ b/doc/bugs/transitive_dependencies.mdwn @@ -65,4 +65,4 @@ Downsides here: modification to plugins/brokenlinks causes an unnecessary update of plugins, and could be solved by adding more dependency types.) ---[[Joey]] +[[done]] --[[Joey]] diff --git a/doc/todo/dependency_types.mdwn b/doc/todo/dependency_types.mdwn index f13f1448e..f46a6a7c6 100644 --- a/doc/todo/dependency_types.mdwn +++ b/doc/todo/dependency_types.mdwn @@ -162,14 +162,13 @@ Link dependencies: * `add_depends($page, $spec, links => 1, presence => 1)` adds a links + presence dependency. -* `refresh` only rebuilds a page with a links dependency if - pages matched by the pagespec gain or lose links. (What the link - actually points to may change independent of this, due to changes - elsewhere, without it firing.) +* Use backlinks change code to detect changes to link dependencies too. * So, brokenlinks can fire whenever any links in any of the pages it's tracking change, or when pages are added or removed. TODO: How to determine if a pagespec is valid to be used with a links dependency? Use the same simple pagespecs that are valid for presence -dependencies? +dependencies? Seems ok. + +[[done]] -- cgit v1.2.3 From c869398e2b5e202145ad3c14d96d520779a462e8 Mon Sep 17 00:00:00 2001 From: Joey Hess Date: Mon, 5 Oct 2009 15:43:37 -0400 Subject: typo --- debian/changelog | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/debian/changelog b/debian/changelog index 363bb9dbd..abbd87abc 100644 --- a/debian/changelog +++ b/debian/changelog @@ -22,7 +22,7 @@ ikiwiki (3.14159266) UNRELEASED; urgency=low * inline: Use a presence dependency in quick mode. * brokenlinks: Use a link dependency. This makes it much more efficient, only updating when really necessary. - * oprhans: Use a combination of precense and link dependencies. + * orphans: Use a combination of precense and link dependencies. This makes it more efficient. It also fixes a longstanding bug, where if only a small set of pages were considered by orphans, changes to links on other pages failed to cause an update. -- cgit v1.2.3 From c21f9e70936566daaf06fff21349f4584ee42906 Mon Sep 17 00:00:00 2001 From: Joey Hess Date: Mon, 5 Oct 2009 15:44:26 -0400 Subject: pagestats: Use a combination of precense and link dependencies. This makes it more efficient. It also fixes the same bug that I fixed in orphans recently, that only changes to the set of displayed pages were considered (or amoung), which missed changes to links on other pages to those. Probably this bug was never noticed because pagestats is most often put on a blog type page, which gets updated anyway when posts change, and thus the tag cloud was updated. --- IkiWiki/Plugin/pagestats.pm | 11 +++++++---- debian/changelog | 6 +++--- 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/IkiWiki/Plugin/pagestats.pm b/IkiWiki/Plugin/pagestats.pm index 874ead7e6..00b919325 100644 --- a/IkiWiki/Plugin/pagestats.pm +++ b/IkiWiki/Plugin/pagestats.pm @@ -35,10 +35,13 @@ sub preprocess (@) { $params{pages}="*" unless defined $params{pages}; my $style = ($params{style} or 'cloud'); - # Needs to update whenever a page is added or removed, so - # register a dependency. - add_depends($params{page}, $params{pages}); - add_depends($params{page}, $params{among}) if exists $params{among}; + # Needs to update whenever a page is added or removed. + add_depends($params{page}, $params{pages}, exists => 1); + # Also needs to update when any page with links changes, + # in case the links point to our displayed pages. + # (Amoung limits this further.) + add_depends($params{page}, exists $params{among} ? $params{among} : "*", + links => 1); my %counts; my $max = 0; diff --git a/debian/changelog b/debian/changelog index abbd87abc..000203405 100644 --- a/debian/changelog +++ b/debian/changelog @@ -22,9 +22,9 @@ ikiwiki (3.14159266) UNRELEASED; urgency=low * inline: Use a presence dependency in quick mode. * brokenlinks: Use a link dependency. This makes it much more efficient, only updating when really necessary. - * orphans: Use a combination of precense and link dependencies. - This makes it more efficient. It also fixes a longstanding bug, - where if only a small set of pages were considered by orphans, + * orphans, pagestats: Use a combination of precense and link dependencies. + This makes them more efficient. It also fixes a longstanding bug, + where if only a small set of pages were considered by orphans/pagestats, changes to links on other pages failed to cause an update. * Transitive dependencies are now correctly supported. -- cgit v1.2.3 From f1864a64ee7592d54a332fcab27d451f29c7aab6 Mon Sep 17 00:00:00 2001 From: Joey Hess Date: Mon, 5 Oct 2009 16:48:15 -0400 Subject: typo --- debian/changelog | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/debian/changelog b/debian/changelog index 000203405..ab235484d 100644 --- a/debian/changelog +++ b/debian/changelog @@ -22,7 +22,7 @@ ikiwiki (3.14159266) UNRELEASED; urgency=low * inline: Use a presence dependency in quick mode. * brokenlinks: Use a link dependency. This makes it much more efficient, only updating when really necessary. - * orphans, pagestats: Use a combination of precense and link dependencies. + * orphans, pagestats: Use a combination of presence and link dependencies. This makes them more efficient. It also fixes a longstanding bug, where if only a small set of pages were considered by orphans/pagestats, changes to links on other pages failed to cause an update. -- cgit v1.2.3 From a4df28f42a96a2412665fc9aeeccc93a160d02f3 Mon Sep 17 00:00:00 2001 From: Joey Hess Date: Mon, 5 Oct 2009 16:51:33 -0400 Subject: add rebuild handing --- debian/NEWS | 10 ++++++++++ debian/changelog | 2 ++ debian/postinst | 2 +- 3 files changed, 13 insertions(+), 1 deletion(-) diff --git a/debian/NEWS b/debian/NEWS index 808105fd5..520f38815 100644 --- a/debian/NEWS +++ b/debian/NEWS @@ -1,3 +1,13 @@ +ikiwiki (3.14159266) UNRELEASED; urgency=low + + To take advantage of significant performance improvements, all + wikis need to be rebuilt on upgrade to this version. If you + listed your wiki in /etc/ikiwiki/wikilist this will be done + automatically when the Debian package is upgraded. Or use + ikiwiki-mass-rebuild to force a rebuild. + + -- Joey Hess Mon, 05 Oct 2009 16:48:59 -0400 + ikiwiki (3.1415926) unstable; urgency=low In order to fix a performance bug, all wikis need to be rebuilt on diff --git a/debian/changelog b/debian/changelog index ab235484d..89d377769 100644 --- a/debian/changelog +++ b/debian/changelog @@ -27,6 +27,8 @@ ikiwiki (3.14159266) UNRELEASED; urgency=low where if only a small set of pages were considered by orphans/pagestats, changes to links on other pages failed to cause an update. * Transitive dependencies are now correctly supported. + * Rebuild wikis on upgrade to this version to get improved dependency + info. -- Joey Hess Sun, 27 Sep 2009 17:40:03 -0400 diff --git a/debian/postinst b/debian/postinst index 2ba26e5b6..dd4be6e0e 100755 --- a/debian/postinst +++ b/debian/postinst @@ -4,7 +4,7 @@ set -e # Change this when some incompatible change is made that requires # rebuilding all wikis. -firstcompat=3.1415926 +firstcompat=3.14159266 if [ "$1" = configure ] && \ dpkg --compare-versions "$2" lt "$firstcompat"; then -- cgit v1.2.3 From 031d1bf5046ab77c796477a19967e7c0c512c417 Mon Sep 17 00:00:00 2001 From: Joey Hess Date: Mon, 5 Oct 2009 17:03:16 -0400 Subject: use among limit for correctness --- IkiWiki/Plugin/pagestats.pm | 2 +- doc/plugins.mdwn | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/IkiWiki/Plugin/pagestats.pm b/IkiWiki/Plugin/pagestats.pm index 00b919325..0765c1cfa 100644 --- a/IkiWiki/Plugin/pagestats.pm +++ b/IkiWiki/Plugin/pagestats.pm @@ -39,7 +39,7 @@ sub preprocess (@) { add_depends($params{page}, $params{pages}, exists => 1); # Also needs to update when any page with links changes, # in case the links point to our displayed pages. - # (Amoung limits this further.) + # (Among limits this further.) add_depends($params{page}, exists $params{among} ? $params{among} : "*", links => 1); diff --git a/doc/plugins.mdwn b/doc/plugins.mdwn index bd7ee538b..697b4a219 100644 --- a/doc/plugins.mdwn +++ b/doc/plugins.mdwn @@ -1,7 +1,7 @@ Most of ikiwiki's [[features]] are implemented as plugins. Many of these plugins are included with ikiwiki. -[[!pagestats pages="plugins/type/* and !plugins/type/slow"]] +[[!pagestats pages="plugins/type/* and !plugins/type/slow" among="plugins/*"]] There's documentation if you want to [[write]] your own plugins, or you can [[install]] plugins [[contributed|contrib]] by others. -- cgit v1.2.3 From ba71687077f0acd902294f9081eff11f7e843532 Mon Sep 17 00:00:00 2001 From: Joey Hess Date: Mon, 5 Oct 2009 17:10:00 -0400 Subject: note that this old bug affects more stuff now --- doc/bugs/bestlink_change_update_issue.mdwn | 3 +++ 1 file changed, 3 insertions(+) diff --git a/doc/bugs/bestlink_change_update_issue.mdwn b/doc/bugs/bestlink_change_update_issue.mdwn index 5ce4a93d2..fee65c0de 100644 --- a/doc/bugs/bestlink_change_update_issue.mdwn +++ b/doc/bugs/bestlink_change_update_issue.mdwn @@ -11,3 +11,6 @@ calculation in refresh(), which doesn't detect that the link has changed in this case. Still true in 1.43 although the code is much different now.. + +> Still true as of 031d1bf5046ab77c796477a19967e7c0c512c417, +> and now this same problem also affects link dependencies. -- cgit v1.2.3 From 7a520974b59c1a498232512978e4abd926292066 Mon Sep 17 00:00:00 2001 From: Joey Hess Date: Mon, 5 Oct 2009 17:44:15 -0400 Subject: uh oh, this affects link deps --- doc/bugs/bestlink_change_update_issue.mdwn | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/doc/bugs/bestlink_change_update_issue.mdwn b/doc/bugs/bestlink_change_update_issue.mdwn index fee65c0de..211a78332 100644 --- a/doc/bugs/bestlink_change_update_issue.mdwn +++ b/doc/bugs/bestlink_change_update_issue.mdwn @@ -1,16 +1,15 @@ * Has bugs updating things if the bestlink of a page changes due to adding/removing a page. For example, if Foo/Bar links to "Baz", which is Foo/Baz, and Foo/Bar/Baz gets added, it will update the links in Foo/Bar - to point to it, but will forget to update the linkbacks in Foo/Baz. + to point to it, but will forget to update the backlinks in Foo/Baz. -* And if Foo/Bar/Baz is then removed, it forgets to update Foo/Bar to link - back to Foo/Baz. +* And if Foo/Bar/Baz is then removed, Foo/Bar gets a broken link, + instead of changing back to linking to Foo/Baz. -As of 1.33, this is still true. The buggy code is the %linkchanged -calculation in refresh(), which doesn't detect that the link has changed in -this case. +This old bug still exists as of 031d1bf5046ab77c796477a19967e7c0c512c417. +and now this same problem also affects link dependencies. -Still true in 1.43 although the code is much different now.. - -> Still true as of 031d1bf5046ab77c796477a19967e7c0c512c417, -> and now this same problem also affects link dependencies. +(Some of) The buggy code is in `find_changed_links` +which doesn't detect that the link has changed in +this case, because when it looks at where the `%oldlinks` link to, +it does so after having updated state to add/remove the page. -- cgit v1.2.3 From 0cb9e588e4253d317945399120a1ef5780b59d7a Mon Sep 17 00:00:00 2001 From: Joey Hess Date: Mon, 5 Oct 2009 20:54:38 -0400 Subject: add among limit to pagestats --- doc/examples/blog/index.mdwn | 2 +- doc/examples/blog/tags.mdwn | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/examples/blog/index.mdwn b/doc/examples/blog/index.mdwn index aef46eb68..01b714fcd 100644 --- a/doc/examples/blog/index.mdwn +++ b/doc/examples/blog/index.mdwn @@ -1,4 +1,4 @@ -[[!pagestats pages="./tags/*"]] +[[!pagestats pages="./tags/*" among="./posts/*"]] Welcome to my blog. diff --git a/doc/examples/blog/tags.mdwn b/doc/examples/blog/tags.mdwn index 53cc8d368..b5eca5b71 100644 --- a/doc/examples/blog/tags.mdwn +++ b/doc/examples/blog/tags.mdwn @@ -1,3 +1,3 @@ -[[!pagestats pages="./tags/*"]] +[[!pagestats pages="./tags/*" among="./posts/*"]] On the right you can see the tag cloud for this blog. -- cgit v1.2.3 From fd7b5767d3d377185838895d04f51288f0889a59 Mon Sep 17 00:00:00 2001 From: Joey Hess Date: Mon, 5 Oct 2009 21:24:55 -0400 Subject: new link change detection method and general code rework This new method for determining when links on pages have changed should be more efficient, since it avoids double calculation of the bestlinks. It also allows collecting data about the old links, before the scan pass, so the data is accurate when pages move around and bestlinks change. Also got some code back to a saner indent level. --- IkiWiki/Render.pm | 242 ++++++++++++++++++++++++++---------------------------- 1 file changed, 116 insertions(+), 126 deletions(-) diff --git a/IkiWiki/Render.pm b/IkiWiki/Render.pm index 599bb26e2..fe0b3138a 100644 --- a/IkiWiki/Render.pm +++ b/IkiWiki/Render.pm @@ -58,52 +58,6 @@ sub backlinks ($) { return @links; } -sub find_changed_links (@_) { - my %linkchanged; - my %linkchangers; - foreach my $file (@_) { - my $page=pagename($file); - - if (exists $links{$page}) { - foreach my $l (@{$links{$page}}) { - my $link=bestlink($page, $l); - if (length $link) { - if (! exists $oldlinks{$page} || - ! grep { bestlink($page, $_) eq $link } @{$oldlinks{$page}}) { - $linkchanged{$link}=1; - $linkchangers{lc($page)}=1; - } - } - else { - if (! grep { lc $_ eq lc $l } @{$oldlinks{$page}}) { - $linkchangers{lc($page)}=1 - } - } - - } - } - if (exists $oldlinks{$page}) { - foreach my $l (@{$oldlinks{$page}}) { - my $link=bestlink($page, $l); - if (length $link) { - if (! exists $links{$page} || - ! grep { bestlink($page, $_) eq $link } @{$links{$page}}) { - $linkchanged{$link}=1; - $linkchangers{lc($page)}=1; - } - } - else { - if (! grep { lc $_ eq lc $l } @{$links{$page}}) { - $linkchangers{lc($page)}=1 - } - } - } - } - } - - return \%linkchanged, \%linkchangers; -} - sub genpage ($$) { my $page=shift; my $content=shift; @@ -389,6 +343,7 @@ sub refresh () { my ($files, $exists)=find_src_files(); my (%rendered, @add, @del, @internal, @internal_change); + # check for added or removed pages foreach my $file (@$files) { my $page=pagename($file); @@ -452,10 +407,11 @@ sub refresh () { $stat[9] > $pagemtime{$page} || $forcerebuild{$page}) { $pagemtime{$page}=$stat[9]; + if (isinternal($page)) { - push @internal_change, $file; # Preprocess internal page in scan-only mode. preprocess($page, $page, readfile($srcfile), 1); + push @internal_change, $file; } else { push @needsbuild, $file; @@ -464,7 +420,19 @@ sub refresh () { } run_hooks(needsbuild => sub { shift->(\@needsbuild) }); - # scan and render files + # before scanning, make a note of where pages' + # old links pointed + my %oldlink_targets; + foreach my $file (@needsbuild, @del) { + my $page=pagename($file); + if (exists $oldlinks{$page}) { + foreach my $l (@{$oldlinks{$page}}) { + $oldlink_targets{$page}{$l}=bestlink($page, $l); + } + } + } + + # scan and render changed files foreach my $file (@needsbuild) { debug(sprintf(gettext("scanning %s"), $file)); scan($file); @@ -499,99 +467,121 @@ sub refresh () { } } } - - if (%rendered || @del || @internal || @internal_change) { + + # determine which links, on what pages, have changed + my %backlinkchanged; + my %linkchangers; + foreach my $file (@needsbuild, @del) { + my $page=pagename($file); + my %link_targets; + if (exists $links{$page}) { + foreach my $l (@{$links{$page}}) { + my $target=bestlink($page, $l); + if (! exists $oldlink_targets{$page}{$l} || + $target ne $oldlink_targets{$page}{$l}) { + $backlinkchanged{$l}=1; + $linkchangers{lc($page)}=1; + } + delete $oldlink_targets{$page}{$l}; + } + } + if (exists $oldlink_targets{$page} && + %{$oldlink_targets{$page}}) { + foreach my $target (keys %{$oldlink_targets{$page}}) { + $backlinkchanged{$target}=1; + } + $linkchangers{lc($page)}=1; + } + } + %oldlink_targets=(); + + # rebuild dependant pages, recursively + my $deps=(@needsbuild || @del || @internal || @internal_change); + do { + $deps=0; my @changed=(keys %rendered, @del); - my ($linkchanged, $linkchangers)=find_changed_links(@changed); - - my $unsettled; - do { - $unsettled=0; - @changed=(keys %rendered, @del); - my @exists_changed=(@add, @del); + my @exists_changed=(@add, @del); - my %lc_changed = map { lc(pagename($_)) => 1 } @changed; - my %lc_exists_changed = map { lc(pagename($_)) => 1 } @exists_changed; + my %lc_changed = map { lc(pagename($_)) => 1 } @changed; + my %lc_exists_changed = map { lc(pagename($_)) => 1 } @exists_changed; - # rebuild dependant pages - foreach my $f (@$files) { - next if $rendered{$f}; - my $p=pagename($f); - my $reason = undef; + foreach my $f (@$files) { + next if $rendered{$f}; + my $p=pagename($f); + my $reason = undef; - if (exists $depends_simple{$p}) { - foreach my $d (keys %{$depends_simple{$p}}) { - if (($depends_simple{$p}{$d} & $IkiWiki::DEPEND_CONTENT && - $lc_changed{$d}) - || - ($depends_simple{$p}{$d} & $IkiWiki::DEPEND_PRESENCE && - $lc_exists_changed{$d}) - || - ($depends_simple{$p}{$d} & $IkiWiki::DEPEND_LINKS && - $linkchangers->{$d}) - ) { - $reason = $d; - last; - } + if (exists $depends_simple{$p}) { + foreach my $d (keys %{$depends_simple{$p}}) { + if (($depends_simple{$p}{$d} & $IkiWiki::DEPEND_CONTENT && + $lc_changed{$d}) + || + ($depends_simple{$p}{$d} & $IkiWiki::DEPEND_PRESENCE && + $lc_exists_changed{$d}) + || + ($depends_simple{$p}{$d} & $IkiWiki::DEPEND_LINKS && + $linkchangers{$d}) + ) { + $reason = $d; + last; } } + } - if (exists $depends{$p} && ! defined $reason) { - D: foreach my $d (keys %{$depends{$p}}) { - my $sub=pagespec_translate($d); - next if $@ || ! defined $sub; - - # only consider internal files - # if the page explicitly depends - # on such files - my $internal_dep=$d =~ /internal\(/; - - my @candidates; - if ($depends{$p}{$d} & $IkiWiki::DEPEND_PRESENCE) { - @candidates=@exists_changed; - push @candidates, @internal - if $internal_dep; - } - if (($depends{$p}{$d} & ($IkiWiki::DEPEND_CONTENT | $IkiWiki::DEPEND_LINKS))) { - @candidates=@changed; - push @candidates, @internal, @internal_change - if $internal_dep; - } + if (exists $depends{$p} && ! defined $reason) { + D: foreach my $d (keys %{$depends{$p}}) { + my $sub=pagespec_translate($d); + next if $@ || ! defined $sub; + + # only consider internal files + # if the page explicitly depends + # on such files + my $internal_dep=$d =~ /internal\(/; + + my @candidates; + if ($depends{$p}{$d} & $IkiWiki::DEPEND_PRESENCE) { + @candidates=@exists_changed; + push @candidates, @internal + if $internal_dep; + } + if (($depends{$p}{$d} & ($IkiWiki::DEPEND_CONTENT | $IkiWiki::DEPEND_LINKS))) { + @candidates=@changed; + push @candidates, @internal, @internal_change + if $internal_dep; + } - foreach my $file (@candidates) { - next if $file eq $f; - my $page=pagename($file); - if ($sub->($page, location => $p)) { - if ($depends{$p}{$d} & $IkiWiki::DEPEND_LINKS) { - next unless $linkchangers->{lc($page)}; - } - $reason = $page; - last D; + foreach my $file (@candidates) { + next if $file eq $f; + my $page=pagename($file); + if ($sub->($page, location => $p)) { + if ($depends{$p}{$d} & $IkiWiki::DEPEND_LINKS) { + next unless $linkchangers{lc($page)}; } + $reason = $page; + last D; } } } - - if (defined $reason) { - debug(sprintf(gettext("building %s, which depends on %s"), $f, $reason)); - render($f); - $rendered{$f}=1; - $unsettled=1; - last; - } } - } while $unsettled; - - # update backlinks at end - foreach my $link (keys %{$linkchanged}) { - my $linkfile=$pagesources{$link}; - if (defined $linkfile) { - next if $rendered{$linkfile}; - debug(sprintf(gettext("building %s, to update its backlinks"), $linkfile)); - render($linkfile); - $rendered{$linkfile}=1; + + if (defined $reason) { + debug(sprintf(gettext("building %s, which depends on %s"), $f, $reason)); + render($f); + $rendered{$f}=1; + $deps=1; + last; } } + } while $deps; + + # update backlinks + foreach my $link (keys %backlinkchanged) { + my $linkfile=$pagesources{$link}; + if (defined $linkfile) { + next if $rendered{$linkfile}; + debug(sprintf(gettext("building %s, to update its backlinks"), $linkfile)); + render($linkfile); + $rendered{$linkfile}=1; + } } # remove no longer rendered files -- cgit v1.2.3 From 534518792d95fb51f6d49c0c48f3f8b3b7398df3 Mon Sep 17 00:00:00 2001 From: Joey Hess Date: Mon, 5 Oct 2009 22:30:14 -0400 Subject: update --- doc/bugs/bestlink_change_update_issue.mdwn | 26 ++++++++++++++++++++------ 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/doc/bugs/bestlink_change_update_issue.mdwn b/doc/bugs/bestlink_change_update_issue.mdwn index 211a78332..8a526e821 100644 --- a/doc/bugs/bestlink_change_update_issue.mdwn +++ b/doc/bugs/bestlink_change_update_issue.mdwn @@ -3,13 +3,27 @@ Foo/Baz, and Foo/Bar/Baz gets added, it will update the links in Foo/Bar to point to it, but will forget to update the backlinks in Foo/Baz. + The buggy code is in `refresh()`, when it determines what + links, on what pages, have changed. It only looks at + changed/added/deleted pages when doing this. But when Foo/Bar/Baz + is added, Foo/Bar is not changed -- so the change it its + backlinks is not noticed. + + To fix this, it needs to consider, when rebuilding Foo/Bar for the changed + links, what oldlinks Foo/Bar had. If one of the oldlinks linked to + Foo/Baz, and not links to Foo/Bar/Baz, it could then rebuild Foo/Baz. + + Problem is that in order to do that, it needs to be able to tell that + the oldlinks linked to Foo/Baz. Which would mean either calculating + all links before the scan phase, or keeping a copy of the backlinks + from the last build, and using that. The first option would be a lot + of work for this minor issue.. it might be less expensive to just rebuild + *all* pages that Foo/Bar links to. + + Keeping a copy of the backlinks has some merit. It could also be + incrementally updated. + * And if Foo/Bar/Baz is then removed, Foo/Bar gets a broken link, instead of changing back to linking to Foo/Baz. This old bug still exists as of 031d1bf5046ab77c796477a19967e7c0c512c417. -and now this same problem also affects link dependencies. - -(Some of) The buggy code is in `find_changed_links` -which doesn't detect that the link has changed in -this case, because when it looks at where the `%oldlinks` link to, -it does so after having updated state to add/remove the page. -- cgit v1.2.3 From 577eed0e7efaf1844d5e3f18a95e699f1bc831c5 Mon Sep 17 00:00:00 2001 From: Joey Hess Date: Mon, 5 Oct 2009 23:54:29 -0400 Subject: split up refresh I'd rather have the global variables than the 300 line function --- IkiWiki/Render.pm | 303 ++++++++++++++++++++++++++++-------------------------- 1 file changed, 157 insertions(+), 146 deletions(-) diff --git a/IkiWiki/Render.pm b/IkiWiki/Render.pm index fe0b3138a..c07be98f8 100644 --- a/IkiWiki/Render.pm +++ b/IkiWiki/Render.pm @@ -7,7 +7,9 @@ use strict; use IkiWiki; use Encode; -my %backlinks; +my (%backlinks, %rendered, @new, @del, @internal, @internal_change, @files, + %page_exists, %oldlink_targets, @needsbuild, %backlinkchanged, + %linkchangers); our %brokenlinks; my $links_calculated=0; @@ -147,6 +149,8 @@ sub genpage ($$) { sub scan ($) { my $file=shift; + debug(sprintf(gettext("scanning %s"), $file)); + my $type=pagetype($file); if (defined $type) { my $srcfile=srcfile($file); @@ -202,8 +206,11 @@ sub fast_file_copy (@) { } } -sub render ($) { +sub render ($$) { my $file=shift; + return if $rendered{$file}; + debug(shift); + $rendered{$file}=1; my $type=pagetype($file); my $srcfile=srcfile($file); @@ -273,7 +280,7 @@ sub srcdir_check () { } sub find_src_files () { - my (@files, %pages); + my @ret; eval q{use File::Find}; error($@) if $@; find({ @@ -290,12 +297,12 @@ sub find_src_files () { } else { $f=~s/^\Q$config{srcdir}\E\/?//; - push @files, $f; - my $pagename = pagename($f); - if ($pages{$pagename}) { - debug(sprintf(gettext("%s has multiple possible source pages"), $pagename)); + push @ret, $f; + my $page = pagename($f); + if ($page_exists{$page}) { + debug(sprintf(gettext("%s has multiple possible source pages"), $page)); } - $pages{$pagename}=1; + $page_exists{$page}=1; } } }, @@ -321,9 +328,9 @@ sub find_src_files () { if (! -l "$config{srcdir}/$f" && ! -e _) { my $page=pagename($f); - if (! $pages{$page}) { - push @files, $f; - $pages{$page}=1; + if (! $page_exists{$page}) { + push @ret, $f; + $page_exists{$page}=1; } } } @@ -331,21 +338,11 @@ sub find_src_files () { }, }, $dir); }; - - # Returns a list of all source files found, and a hash of - # the corresponding page names. - return \@files, \%pages; + return \@ret; } -sub refresh () { - srcdir_check(); - run_hooks(refresh => sub { shift->() }); - my ($files, $exists)=find_src_files(); - - my (%rendered, @add, @del, @internal, @internal_change); - - # check for added or removed pages - foreach my $file (@$files) { +sub process_new_files () { + foreach my $file (@files) { my $page=pagename($file); if (exists $pagesources{$page} && $pagesources{$page} ne $file) { # the page has changed its type @@ -357,7 +354,7 @@ sub refresh () { push @internal, $file; } else { - push @add, $file; + push @new, $file; if ($config{getctime} && -e "$config{srcdir}/$file") { eval { my $time=rcs_getctime("$config{srcdir}/$file"); @@ -374,8 +371,11 @@ sub refresh () { } } } +} + +sub process_del_files () { foreach my $page (keys %pagemtime) { - if (! $exists->{$page}) { + if (! $page_exists{$page}) { if (isinternal($page)) { push @internal, $pagesources{$page}; } @@ -397,10 +397,10 @@ sub refresh () { } } } +} - # find changed and new files - my @needsbuild; - foreach my $file (@$files) { +sub find_needsbuild () { + foreach my $file (@files) { my $page=pagename($file); my ($srcfile, @stat)=srcfile_stat($file); if (! exists $pagemtime{$page} || @@ -418,11 +418,9 @@ sub refresh () { } } } - run_hooks(needsbuild => sub { shift->(\@needsbuild) }); +} - # before scanning, make a note of where pages' - # old links pointed - my %oldlink_targets; +sub calculate_old_links () { foreach my $file (@needsbuild, @del) { my $page=pagename($file); if (exists $oldlinks{$page}) { @@ -431,46 +429,42 @@ sub refresh () { } } } +} - # scan and render changed files - foreach my $file (@needsbuild) { - debug(sprintf(gettext("scanning %s"), $file)); - scan($file); - } - calculate_links(); - foreach my $file (@needsbuild) { - debug(sprintf(gettext("building %s"), $file)); - render($file); - $rendered{$file}=1; +sub derender_internal ($) { + my $file=shift; + my $page=pagename($file); + delete $depends{$page}; + delete $depends_simple{$page}; + foreach my $old (@{$renderedfiles{$page}}) { + delete $destsources{$old}; } - foreach my $file (@internal, @internal_change) { - # internal pages are not rendered - my $page=pagename($file); - delete $depends{$page}; - delete $depends_simple{$page}; - foreach my $old (@{$renderedfiles{$page}}) { - delete $destsources{$old}; + $renderedfiles{$page}=[]; +} + +sub render_linkers () { + foreach my $f (@new, @del) { + my $p=pagename($f); + foreach my $page (keys %{$backlinks{$p}}) { + my $file=$pagesources{$page}; + render($file, sprintf(gettext("building %s, which links to %s"), $file, $p)); } - $renderedfiles{$page}=[]; } - - # rebuild pages that link to added or removed pages - if (@add || @del) { - foreach my $f (@add, @del) { - my $p=pagename($f); - foreach my $page (keys %{$backlinks{$p}}) { - my $file=$pagesources{$page}; - next if $rendered{$file}; - debug(sprintf(gettext("building %s, which links to %s"), $file, $p)); - render($file); - $rendered{$file}=1; +} + +sub remove_unrendered () { + foreach my $src (keys %rendered) { + my $page=pagename($src); + foreach my $file (@{$oldrenderedfiles{$page}}) { + if (! grep { $_ eq $file } @{$renderedfiles{$page}}) { + debug(sprintf(gettext("removing %s, no longer built by %s"), $file, $page)); + prune($config{destdir}."/".$file); } } } - - # determine which links, on what pages, have changed - my %backlinkchanged; - my %linkchangers; +} + +sub calculate_changed_links () { foreach my $file (@needsbuild, @del) { my $page=pagename($file); my %link_targets; @@ -493,107 +487,124 @@ sub refresh () { $linkchangers{lc($page)}=1; } } - %oldlink_targets=(); - - # rebuild dependant pages, recursively - my $deps=(@needsbuild || @del || @internal || @internal_change); - do { - $deps=0; - my @changed=(keys %rendered, @del); - my @exists_changed=(@add, @del); +} + +sub render_dependent () { + my @changed=(keys %rendered, @del); + my @exists_changed=(@new, @del); - my %lc_changed = map { lc(pagename($_)) => 1 } @changed; - my %lc_exists_changed = map { lc(pagename($_)) => 1 } @exists_changed; + my %lc_changed = map { lc(pagename($_)) => 1 } @changed; + my %lc_exists_changed = map { lc(pagename($_)) => 1 } @exists_changed; - foreach my $f (@$files) { - next if $rendered{$f}; - my $p=pagename($f); - my $reason = undef; + foreach my $f (@files) { + next if $rendered{$f}; + my $p=pagename($f); + my $reason = undef; - if (exists $depends_simple{$p}) { - foreach my $d (keys %{$depends_simple{$p}}) { - if (($depends_simple{$p}{$d} & $IkiWiki::DEPEND_CONTENT && - $lc_changed{$d}) - || - ($depends_simple{$p}{$d} & $IkiWiki::DEPEND_PRESENCE && - $lc_exists_changed{$d}) - || - ($depends_simple{$p}{$d} & $IkiWiki::DEPEND_LINKS && - $linkchangers{$d}) - ) { - $reason = $d; - last; - } + if (exists $depends_simple{$p}) { + foreach my $d (keys %{$depends_simple{$p}}) { + if (($depends_simple{$p}{$d} & $IkiWiki::DEPEND_CONTENT && + $lc_changed{$d}) + || + ($depends_simple{$p}{$d} & $IkiWiki::DEPEND_PRESENCE && + $lc_exists_changed{$d}) + || + ($depends_simple{$p}{$d} & $IkiWiki::DEPEND_LINKS && + $linkchangers{$d}) + ) { + $reason = $d; + last; } } + } - if (exists $depends{$p} && ! defined $reason) { - D: foreach my $d (keys %{$depends{$p}}) { - my $sub=pagespec_translate($d); - next if $@ || ! defined $sub; - - # only consider internal files - # if the page explicitly depends - # on such files - my $internal_dep=$d =~ /internal\(/; - - my @candidates; - if ($depends{$p}{$d} & $IkiWiki::DEPEND_PRESENCE) { - @candidates=@exists_changed; - push @candidates, @internal - if $internal_dep; - } - if (($depends{$p}{$d} & ($IkiWiki::DEPEND_CONTENT | $IkiWiki::DEPEND_LINKS))) { - @candidates=@changed; - push @candidates, @internal, @internal_change - if $internal_dep; - } + if (exists $depends{$p} && ! defined $reason) { + D: foreach my $d (keys %{$depends{$p}}) { + my $sub=pagespec_translate($d); + next if $@ || ! defined $sub; + + # only consider internal files + # if the page explicitly depends + # on such files + my $internal_dep=$d =~ /internal\(/; + + my @candidates; + if ($depends{$p}{$d} & $IkiWiki::DEPEND_PRESENCE) { + @candidates=@exists_changed; + push @candidates, @internal + if $internal_dep; + } + if (($depends{$p}{$d} & ($IkiWiki::DEPEND_CONTENT | $IkiWiki::DEPEND_LINKS))) { + @candidates=@changed; + push @candidates, @internal, @internal_change + if $internal_dep; + } - foreach my $file (@candidates) { - next if $file eq $f; - my $page=pagename($file); - if ($sub->($page, location => $p)) { - if ($depends{$p}{$d} & $IkiWiki::DEPEND_LINKS) { - next unless $linkchangers{lc($page)}; - } - $reason = $page; - last D; + foreach my $file (@candidates) { + next if $file eq $f; + my $page=pagename($file); + if ($sub->($page, location => $p)) { + if ($depends{$p}{$d} & $IkiWiki::DEPEND_LINKS) { + next unless $linkchangers{lc($page)}; } + $reason = $page; + last D; } } } + } - if (defined $reason) { - debug(sprintf(gettext("building %s, which depends on %s"), $f, $reason)); - render($f); - $rendered{$f}=1; - $deps=1; - last; - } + if (defined $reason) { + render($f, sprintf(gettext("building %s, which depends on %s"), $f, $reason)); + return 1; } - } while $deps; + } - # update backlinks + return 0; +} + +sub render_backlinks () { foreach my $link (keys %backlinkchanged) { my $linkfile=$pagesources{$link}; if (defined $linkfile) { - next if $rendered{$linkfile}; - debug(sprintf(gettext("building %s, to update its backlinks"), $linkfile)); - render($linkfile); - $rendered{$linkfile}=1; + render($linkfile, sprintf(gettext("building %s, to update its backlinks"), $linkfile)); } } +} - # remove no longer rendered files - foreach my $src (keys %rendered) { - my $page=pagename($src); - foreach my $file (@{$oldrenderedfiles{$page}}) { - if (! grep { $_ eq $file } @{$renderedfiles{$page}}) { - debug(sprintf(gettext("removing %s, no longer built by %s"), $file, $page)); - prune($config{destdir}."/".$file); - } - } +sub refresh () { + srcdir_check(); + run_hooks(refresh => sub { shift->() }); + @files=@{find_src_files()}; + process_new_files(); + process_del_files(); + find_needsbuild(); + run_hooks(needsbuild => sub { shift->(\@needsbuild) }); + calculate_old_links(); + + foreach my $file (@needsbuild) { + scan($file); + } + + calculate_links(); + + foreach my $file (@needsbuild) { + render($file, sprintf(gettext("building %s"), $file)); + } + + foreach my $file (@internal, @internal_change) { + derender_internal($file); } + + calculate_changed_links(); + render_linkers(); + + if (@needsbuild || @del || @internal || @internal_change) { + 1 while render_dependent(); + } + + render_backlinks(); + remove_unrendered(); if (@del) { run_hooks(delete => sub { shift->(@del) }); -- cgit v1.2.3 From 96b1f9519270db39d4056878907dec2d6976fce4 Mon Sep 17 00:00:00 2001 From: Joey Hess Date: Tue, 6 Oct 2009 00:06:37 -0400 Subject: refresh refactor 2 killed one global --- IkiWiki/Render.pm | 86 +++++++++++++++++++++++++++++-------------------------- 1 file changed, 46 insertions(+), 40 deletions(-) diff --git a/IkiWiki/Render.pm b/IkiWiki/Render.pm index c07be98f8..5336d4f54 100644 --- a/IkiWiki/Render.pm +++ b/IkiWiki/Render.pm @@ -8,7 +8,7 @@ use IkiWiki; use Encode; my (%backlinks, %rendered, @new, @del, @internal, @internal_change, @files, - %page_exists, %oldlink_targets, @needsbuild, %backlinkchanged, + %page_exists, %oldlink_targets, %backlinkchanged, %linkchangers); our %brokenlinks; my $links_calculated=0; @@ -400,6 +400,7 @@ sub process_del_files () { } sub find_needsbuild () { + my @needsbuild; foreach my $file (@files) { my $page=pagename($file); my ($srcfile, @stat)=srcfile_stat($file); @@ -418,15 +419,15 @@ sub find_needsbuild () { } } } + return @needsbuild; } -sub calculate_old_links () { - foreach my $file (@needsbuild, @del) { - my $page=pagename($file); - if (exists $oldlinks{$page}) { - foreach my $l (@{$oldlinks{$page}}) { - $oldlink_targets{$page}{$l}=bestlink($page, $l); - } +sub calculate_old_links ($) { + my $file=shift; + my $page=pagename($file); + if (exists $oldlinks{$page}) { + foreach my $l (@{$oldlinks{$page}}) { + $oldlink_targets{$page}{$l}=bestlink($page, $l); } } } @@ -442,13 +443,12 @@ sub derender_internal ($) { $renderedfiles{$page}=[]; } -sub render_linkers () { - foreach my $f (@new, @del) { - my $p=pagename($f); - foreach my $page (keys %{$backlinks{$p}}) { - my $file=$pagesources{$page}; - render($file, sprintf(gettext("building %s, which links to %s"), $file, $p)); - } +sub render_linkers ($) { + my $f=shift; + my $p=pagename($f); + foreach my $page (keys %{$backlinks{$p}}) { + my $file=$pagesources{$page}; + render($file, sprintf(gettext("building %s, which links to %s"), $file, $p)); } } @@ -464,28 +464,26 @@ sub remove_unrendered () { } } -sub calculate_changed_links () { - foreach my $file (@needsbuild, @del) { - my $page=pagename($file); - my %link_targets; - if (exists $links{$page}) { - foreach my $l (@{$links{$page}}) { - my $target=bestlink($page, $l); - if (! exists $oldlink_targets{$page}{$l} || - $target ne $oldlink_targets{$page}{$l}) { - $backlinkchanged{$l}=1; - $linkchangers{lc($page)}=1; - } - delete $oldlink_targets{$page}{$l}; +sub calculate_changed_links ($) { + my $file=shift; + my $page=pagename($file); + if (exists $links{$page}) { + foreach my $l (@{$links{$page}}) { + my $target=bestlink($page, $l); + if (! exists $oldlink_targets{$page}{$l} || + $target ne $oldlink_targets{$page}{$l}) { + $backlinkchanged{$l}=1; + $linkchangers{lc($page)}=1; } + delete $oldlink_targets{$page}{$l}; } - if (exists $oldlink_targets{$page} && - %{$oldlink_targets{$page}}) { - foreach my $target (keys %{$oldlink_targets{$page}}) { - $backlinkchanged{$target}=1; - } - $linkchangers{lc($page)}=1; + } + if (exists $oldlink_targets{$page} && + %{$oldlink_targets{$page}}) { + foreach my $target (keys %{$oldlink_targets{$page}}) { + $backlinkchanged{$target}=1; } + $linkchangers{lc($page)}=1; } } @@ -578,9 +576,13 @@ sub refresh () { @files=@{find_src_files()}; process_new_files(); process_del_files(); - find_needsbuild(); + + my @needsbuild=find_needsbuild(); run_hooks(needsbuild => sub { shift->(\@needsbuild) }); - calculate_old_links(); + + foreach my $file (@needsbuild, @del) { + calculate_old_links($file); + } foreach my $file (@needsbuild) { scan($file); @@ -591,13 +593,17 @@ sub refresh () { foreach my $file (@needsbuild) { render($file, sprintf(gettext("building %s"), $file)); } - foreach my $file (@internal, @internal_change) { derender_internal($file); } - - calculate_changed_links(); - render_linkers(); + + foreach my $file (@needsbuild, @del) { + calculate_changed_links($file); + } + + foreach my $file (@new, @del) { + render_linkers($file); + } if (@needsbuild || @del || @internal || @internal_change) { 1 while render_dependent(); -- cgit v1.2.3 From 2a0e6b782c90e92ee038c8db69032cab3f5431f2 Mon Sep 17 00:00:00 2001 From: Joey Hess Date: Tue, 6 Oct 2009 02:00:34 -0400 Subject: refactor 3 Only left one new global --- IkiWiki/Render.pm | 185 +++++++++++++++++++++++++++++++----------------------- 1 file changed, 106 insertions(+), 79 deletions(-) diff --git a/IkiWiki/Render.pm b/IkiWiki/Render.pm index 5336d4f54..7f311ddf9 100644 --- a/IkiWiki/Render.pm +++ b/IkiWiki/Render.pm @@ -7,9 +7,7 @@ use strict; use IkiWiki; use Encode; -my (%backlinks, %rendered, @new, @del, @internal, @internal_change, @files, - %page_exists, %oldlink_targets, %backlinkchanged, - %linkchangers); +my (%backlinks, %rendered); our %brokenlinks; my $links_calculated=0; @@ -280,7 +278,8 @@ sub srcdir_check () { } sub find_src_files () { - my @ret; + my @files; + my %pages; eval q{use File::Find}; error($@) if $@; find({ @@ -297,12 +296,12 @@ sub find_src_files () { } else { $f=~s/^\Q$config{srcdir}\E\/?//; - push @ret, $f; + push @files, $f; my $page = pagename($f); - if ($page_exists{$page}) { + if ($pages{$page}) { debug(sprintf(gettext("%s has multiple possible source pages"), $page)); } - $page_exists{$page}=1; + $pages{$page}=1; } } }, @@ -328,9 +327,9 @@ sub find_src_files () { if (! -l "$config{srcdir}/$f" && ! -e _) { my $page=pagename($f); - if (! $page_exists{$page}) { - push @ret, $f; - $page_exists{$page}=1; + if (! $pages{$page}) { + push @files, $f; + $pages{$page}=1; } } } @@ -338,11 +337,15 @@ sub find_src_files () { }, }, $dir); }; - return \@ret; + return \@files, \%pages; } -sub process_new_files () { - foreach my $file (@files) { +sub find_new_files ($) { + my $files=shift; + my @new; + my @internal_new; + + foreach my $file (@$files) { my $page=pagename($file); if (exists $pagesources{$page} && $pagesources{$page} ne $file) { # the page has changed its type @@ -351,7 +354,7 @@ sub process_new_files () { $pagesources{$page}=$file; if (! $pagemtime{$page}) { if (isinternal($page)) { - push @internal, $file; + push @internal_new, $file; } else { push @new, $file; @@ -371,13 +374,19 @@ sub process_new_files () { } } } + + return \@new, \@internal_new; } -sub process_del_files () { +sub find_del_files ($) { + my $pages=shift; + my @del; + my @internal_del; + foreach my $page (keys %pagemtime) { - if (! $page_exists{$page}) { + if (! $pages->{$page}) { if (isinternal($page)) { - push @internal, $pagesources{$page}; + push @internal_del, $pagesources{$page}; } else { debug(sprintf(gettext("removing old page %s"), $page)); @@ -397,11 +406,15 @@ sub process_del_files () { } } } + + return \@del, \@internal_del; } -sub find_needsbuild () { - my @needsbuild; - foreach my $file (@files) { +sub find_changed ($) { + my $files=shift; + my @changed; + my @internal_changed; + foreach my $file (@$files) { my $page=pagename($file); my ($srcfile, @stat)=srcfile_stat($file); if (! exists $pagemtime{$page} || @@ -412,24 +425,28 @@ sub find_needsbuild () { if (isinternal($page)) { # Preprocess internal page in scan-only mode. preprocess($page, $page, readfile($srcfile), 1); - push @internal_change, $file; + push @internal_changed, $file; } else { - push @needsbuild, $file; + push @changed, $file; } } } - return @needsbuild; + return \@changed, \@internal_changed; } -sub calculate_old_links ($) { - my $file=shift; - my $page=pagename($file); - if (exists $oldlinks{$page}) { - foreach my $l (@{$oldlinks{$page}}) { - $oldlink_targets{$page}{$l}=bestlink($page, $l); +sub calculate_old_links ($$) { + my ($changed, $del)=@_; + my %oldlink_targets; + foreach my $file (@$changed, @$del) { + my $page=pagename($file); + if (exists $oldlinks{$page}) { + foreach my $l (@{$oldlinks{$page}}) { + $oldlink_targets{$page}{$l}=bestlink($page, $l); + } } } + return \%oldlink_targets; } sub derender_internal ($) { @@ -464,37 +481,48 @@ sub remove_unrendered () { } } -sub calculate_changed_links ($) { - my $file=shift; - my $page=pagename($file); - if (exists $links{$page}) { - foreach my $l (@{$links{$page}}) { - my $target=bestlink($page, $l); - if (! exists $oldlink_targets{$page}{$l} || - $target ne $oldlink_targets{$page}{$l}) { - $backlinkchanged{$l}=1; - $linkchangers{lc($page)}=1; +sub calculate_changed_links ($$$) { + my ($changed, $del, $oldlink_targets)=@_; + + my (%backlinkchanged, %linkchangers); + + foreach my $file (@$changed, @$del) { + my $page=pagename($file); + + if (exists $links{$page}) { + foreach my $l (@{$links{$page}}) { + my $target=bestlink($page, $l); + if (! exists $oldlink_targets->{$page}{$l} || + $target ne $oldlink_targets->{$page}{$l}) { + $backlinkchanged{$l}=1; + $linkchangers{lc($page)}=1; + } + delete $oldlink_targets->{$page}{$l}; } - delete $oldlink_targets{$page}{$l}; } - } - if (exists $oldlink_targets{$page} && - %{$oldlink_targets{$page}}) { - foreach my $target (keys %{$oldlink_targets{$page}}) { - $backlinkchanged{$target}=1; + if (exists $oldlink_targets->{$page} && + %{$oldlink_targets->{$page}}) { + foreach my $target (keys %{$oldlink_targets->{$page}}) { + $backlinkchanged{$target}=1; + } + $linkchangers{lc($page)}=1; } - $linkchangers{lc($page)}=1; } + + return \%backlinkchanged, \%linkchangers; } -sub render_dependent () { - my @changed=(keys %rendered, @del); - my @exists_changed=(@new, @del); +sub render_dependent ($$$$$$$) { + my ($files, $new, $internal_new, $del, $internal_del, + $internal_changed, $linkchangers)=@_; + + my @changed=(keys %rendered, @$del); + my @exists_changed=(@$new, @$del); my %lc_changed = map { lc(pagename($_)) => 1 } @changed; my %lc_exists_changed = map { lc(pagename($_)) => 1 } @exists_changed; - foreach my $f (@files) { + foreach my $f (@$files) { next if $rendered{$f}; my $p=pagename($f); my $reason = undef; @@ -508,7 +536,7 @@ sub render_dependent () { $lc_exists_changed{$d}) || ($depends_simple{$p}{$d} & $IkiWiki::DEPEND_LINKS && - $linkchangers{$d}) + $linkchangers->{$d}) ) { $reason = $d; last; @@ -529,12 +557,12 @@ sub render_dependent () { my @candidates; if ($depends{$p}{$d} & $IkiWiki::DEPEND_PRESENCE) { @candidates=@exists_changed; - push @candidates, @internal + push @candidates, @$internal_new, @$internal_del if $internal_dep; } if (($depends{$p}{$d} & ($IkiWiki::DEPEND_CONTENT | $IkiWiki::DEPEND_LINKS))) { @candidates=@changed; - push @candidates, @internal, @internal_change + push @candidates, @$internal_new, @$internal_del, @$internal_changed if $internal_dep; } @@ -543,7 +571,7 @@ sub render_dependent () { my $page=pagename($file); if ($sub->($page, location => $p)) { if ($depends{$p}{$d} & $IkiWiki::DEPEND_LINKS) { - next unless $linkchangers{lc($page)}; + next unless $linkchangers->{lc($page)}; } $reason = $page; last D; @@ -561,8 +589,9 @@ sub render_dependent () { return 0; } -sub render_backlinks () { - foreach my $link (keys %backlinkchanged) { +sub render_backlinks ($) { + my $backlinkchanged=shift; + foreach my $link (keys %$backlinkchanged) { my $linkfile=$pagesources{$link}; if (defined $linkfile) { render($linkfile, sprintf(gettext("building %s, to update its backlinks"), $linkfile)); @@ -573,47 +602,45 @@ sub render_backlinks () { sub refresh () { srcdir_check(); run_hooks(refresh => sub { shift->() }); - @files=@{find_src_files()}; - process_new_files(); - process_del_files(); - - my @needsbuild=find_needsbuild(); - run_hooks(needsbuild => sub { shift->(\@needsbuild) }); - - foreach my $file (@needsbuild, @del) { - calculate_old_links($file); - } - - foreach my $file (@needsbuild) { + my ($files, $pages)=find_src_files(); + my ($new, $internal_new)=find_new_files($files); + my ($del, $internal_del)=find_del_files($pages); + my ($changed, $internal_changed)=find_changed($files); + run_hooks(needsbuild => sub { shift->($changed) }); + my $oldlink_targets=calculate_old_links($changed, $del); + + foreach my $file (@$changed) { scan($file); } calculate_links(); - foreach my $file (@needsbuild) { + foreach my $file (@$changed) { render($file, sprintf(gettext("building %s"), $file)); } - foreach my $file (@internal, @internal_change) { + foreach my $file (@$internal_new, @$internal_del, @$internal_changed) { derender_internal($file); } - foreach my $file (@needsbuild, @del) { - calculate_changed_links($file); - } + my ($backlinkchanged, $linkchangers)=calculate_changed_links($changed, + $del, $oldlink_targets); - foreach my $file (@new, @del) { + foreach my $file (@$new, @$del) { render_linkers($file); } - if (@needsbuild || @del || @internal || @internal_change) { - 1 while render_dependent(); + if (@$changed || @$internal_changed || + @$del || @$internal_del || @$internal_new) { + 1 while render_dependent($files, $new, $internal_new, + $del, $internal_del, $internal_changed, + $linkchangers); } - render_backlinks(); + render_backlinks($backlinkchanged); remove_unrendered(); - if (@del) { - run_hooks(delete => sub { shift->(@del) }); + if (@$del) { + run_hooks(delete => sub { shift->(@$del) }); } if (%rendered) { run_hooks(change => sub { shift->(keys %rendered) }); -- cgit v1.2.3 From 2494a23fdd911eb7e85f2ea66607b4e08d87e927 Mon Sep 17 00:00:00 2001 From: Joey Hess Date: Tue, 6 Oct 2009 04:45:57 -0400 Subject: fix handling of links+content dependency Such a dependency is unlikely, but can happen. --- IkiWiki/Render.pm | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/IkiWiki/Render.pm b/IkiWiki/Render.pm index 7f311ddf9..e86314107 100644 --- a/IkiWiki/Render.pm +++ b/IkiWiki/Render.pm @@ -570,7 +570,8 @@ sub render_dependent ($$$$$$$) { next if $file eq $f; my $page=pagename($file); if ($sub->($page, location => $p)) { - if ($depends{$p}{$d} & $IkiWiki::DEPEND_LINKS) { + if ($depends{$p}{$d} & $IkiWiki::DEPEND_LINKS && + ! $depends{$p}{$d} & $IkiWiki::DEPEND_CONTENT) { next unless $linkchangers->{lc($page)}; } $reason = $page; -- cgit v1.2.3 From af85f62d6fd7c3b437fa527bff3392616d3513dc Mon Sep 17 00:00:00 2001 From: Joey Hess Date: Tue, 6 Oct 2009 17:47:10 -0400 Subject: linkmap: Use a combination of presence and link dependencies. This makes the map be regenerated much less frequently, so larger maps are more practical to use now. --- IkiWiki/Plugin/linkmap.pm | 6 +++--- debian/changelog | 3 +++ doc/ikiwiki/directive/linkmap.mdwn | 4 +--- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/IkiWiki/Plugin/linkmap.pm b/IkiWiki/Plugin/linkmap.pm index d0671ae0e..d7ba68da9 100644 --- a/IkiWiki/Plugin/linkmap.pm +++ b/IkiWiki/Plugin/linkmap.pm @@ -28,9 +28,9 @@ sub preprocess (@) { $params{pages}="*" unless defined $params{pages}; - # Needs to update whenever a page is added, removed, or - # its links change, so register a dependency. - add_depends($params{page}, $params{pages}); + # Needs to update whenever a relevant page is added, or removed, or + # its links change. + add_depends($params{page}, $params{pages}, presence => 1, links => 1); # Can't just return the linkmap here, since the htmlscrubber # scrubs out all tags (with good reason!) diff --git a/debian/changelog b/debian/changelog index 89d377769..a006d3177 100644 --- a/debian/changelog +++ b/debian/changelog @@ -26,6 +26,9 @@ ikiwiki (3.14159266) UNRELEASED; urgency=low This makes them more efficient. It also fixes a longstanding bug, where if only a small set of pages were considered by orphans/pagestats, changes to links on other pages failed to cause an update. + * linkmap: Use a combination of presence and link dependencies. + This makes the map be regenerated much less frequently, so larger + maps are more practical to use now. * Transitive dependencies are now correctly supported. * Rebuild wikis on upgrade to this version to get improved dependency info. diff --git a/doc/ikiwiki/directive/linkmap.mdwn b/doc/ikiwiki/directive/linkmap.mdwn index db79a1491..38cf0fd11 100644 --- a/doc/ikiwiki/directive/linkmap.mdwn +++ b/doc/ikiwiki/directive/linkmap.mdwn @@ -9,9 +9,7 @@ Only links between mapped pages will be shown; links pointing to or from unmapped pages will be omitted. If the pages to include are not specified, the links between all pages (and other files) in the wiki are mapped. For best results, only a small set of pages should be mapped, since otherwise -the map can become very large, unwieldy, and complicated. Also, the map is -rebuilt whenever one of the mapped pages is changed, which can make the -wiki a bit slow. +the map can become very large, unwieldy, and complicated. Here are descriptions of all the supported parameters to the `linkmap` directive: -- cgit v1.2.3 From ba1dfb4ec665f95b4f4217360e08109bcbf7f41b Mon Sep 17 00:00:00 2001 From: Joey Hess Date: Tue, 6 Oct 2009 18:09:46 -0400 Subject: fix support of a single dependency that combines links and exists types This is very common, and the code has to test each type differently, since the list of candidates to test, as well as the test, will vary per type. Much happier with this code now. --- IkiWiki/Render.pm | 65 ++++++++++++++++++++++++++++++++++--------------------- 1 file changed, 40 insertions(+), 25 deletions(-) diff --git a/IkiWiki/Render.pm b/IkiWiki/Render.pm index e86314107..8f9cbf673 100644 --- a/IkiWiki/Render.pm +++ b/IkiWiki/Render.pm @@ -545,38 +545,53 @@ sub render_dependent ($$$$$$$) { } if (exists $depends{$p} && ! defined $reason) { - D: foreach my $d (keys %{$depends{$p}}) { - my $sub=pagespec_translate($d); + foreach my $dep (keys %{$depends{$p}}) { + my $sub=pagespec_translate($dep); next if $@ || ! defined $sub; # only consider internal files # if the page explicitly depends # on such files - my $internal_dep=$d =~ /internal\(/; - - my @candidates; - if ($depends{$p}{$d} & $IkiWiki::DEPEND_PRESENCE) { - @candidates=@exists_changed; - push @candidates, @$internal_new, @$internal_del - if $internal_dep; - } - if (($depends{$p}{$d} & ($IkiWiki::DEPEND_CONTENT | $IkiWiki::DEPEND_LINKS))) { - @candidates=@changed; - push @candidates, @$internal_new, @$internal_del, @$internal_changed - if $internal_dep; - } - - foreach my $file (@candidates) { - next if $file eq $f; - my $page=pagename($file); - if ($sub->($page, location => $p)) { - if ($depends{$p}{$d} & $IkiWiki::DEPEND_LINKS && - ! $depends{$p}{$d} & $IkiWiki::DEPEND_CONTENT) { - next unless $linkchangers->{lc($page)}; + my $internal_dep=$dep =~ /internal\(/; + + my $in=sub { + my $list=shift; + my $type=shift; + foreach my $file ($list) { + next if $file eq $f; + my $page=pagename($file); + if ($sub->($page, location => $p)) { + if ($type == $IkiWiki::DEPEND_LINKS) { + next unless $linkchangers->{lc($page)}; + } + return $page; } - $reason = $page; - last D; } + return undef; + }; + + if ($depends{$p}{$dep} & $IkiWiki::DEPEND_CONTENT) { + last if $reason = + $in->(\@changed, $IkiWiki::DEPEND_CONTENT); + last if $internal_dep && ($reason = + $in->($internal_new, $IkiWiki::DEPEND_CONTENT) || + $in->($internal_del, $IkiWiki::DEPEND_CONTENT) || + $in->($internal_changed, $IkiWiki::DEPEND_CONTENT)); + } + if ($depends{$p}{$dep} & $IkiWiki::DEPEND_PRESENCE) { + last if $reason = + $in->(\@exists_changed, $IkiWiki::DEPEND_PRESENCE); + last if $internal_dep && ($reason = + $in->($internal_new, $IkiWiki::DEPEND_PRESENCE) || + $in->($internal_del, $IkiWiki::DEPEND_PRESENCE)); + } + if ($depends{$p}{$dep} & $IkiWiki::DEPEND_LINKS) { + last if $reason = + $in->(\@changed, $IkiWiki::DEPEND_LINKS); + last if $internal_dep && ($reason = + $in->($internal_new, $IkiWiki::DEPEND_LINKS) || + $in->($internal_del, $IkiWiki::DEPEND_LINKS) || + $in->($internal_changed, $IkiWiki::DEPEND_LINKS)); } } } -- cgit v1.2.3 From 348a6aaee3c13e0afababc4b9bb41743d7227f12 Mon Sep 17 00:00:00 2001 From: Joey Hess Date: Tue, 6 Oct 2009 18:20:11 -0400 Subject: pagespec for links dependencies --- doc/todo/dependency_types.mdwn | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/doc/todo/dependency_types.mdwn b/doc/todo/dependency_types.mdwn index f46a6a7c6..19294bba0 100644 --- a/doc/todo/dependency_types.mdwn +++ b/doc/todo/dependency_types.mdwn @@ -166,9 +166,10 @@ Link dependencies: * So, brokenlinks can fire whenever any links in any of the pages it's tracking change, or when pages are added or removed. - -TODO: How to determine if a pagespec is valid to be used with a links -dependency? Use the same simple pagespecs that are valid for presence -dependencies? Seems ok. +* To determine if a pagespec is valid to be used with a links dependency, + use the same set that are valid for presence dependencies. But also + allow `backlinks()` to be used in it, since that matches pages + that the page links to, which is just what link dependencies are + triggered on. [[done]] -- cgit v1.2.3 From 15fd89d64deaeeee921a02b240d5036bbd896f89 Mon Sep 17 00:00:00 2001 From: Joey Hess Date: Tue, 6 Oct 2009 18:41:09 -0400 Subject: presence dependencies not needed Using just a link dependency is sufficient, since --- IkiWiki/Plugin/linkmap.pm | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/IkiWiki/Plugin/linkmap.pm b/IkiWiki/Plugin/linkmap.pm index d7ba68da9..b8b4cf40d 100644 --- a/IkiWiki/Plugin/linkmap.pm +++ b/IkiWiki/Plugin/linkmap.pm @@ -28,9 +28,8 @@ sub preprocess (@) { $params{pages}="*" unless defined $params{pages}; - # Needs to update whenever a relevant page is added, or removed, or - # its links change. - add_depends($params{page}, $params{pages}, presence => 1, links => 1); + # Needs to update whenever a relevant page's links change. + add_depends($params{page}, $params{pages}, links => 1); # Can't just return the linkmap here, since the htmlscrubber # scrubs out all tags (with good reason!) -- cgit v1.2.3 From 62cc2afcaa7d09f73cb00a7efb15502406743178 Mon Sep 17 00:00:00 2001 From: Joey Hess Date: Tue, 6 Oct 2009 18:44:34 -0400 Subject: update to test backlinks() pagespecs --- t/add_depends.t | 47 +++++++++++++++++++++++++++++++++-------------- 1 file changed, 33 insertions(+), 14 deletions(-) mode change 100644 => 100755 t/add_depends.t diff --git a/t/add_depends.t b/t/add_depends.t old mode 100644 new mode 100755 index 935a57944..68429b24a --- a/t/add_depends.t +++ b/t/add_depends.t @@ -1,7 +1,7 @@ #!/usr/bin/perl use warnings; use strict; -use Test::More tests => 50; +use Test::More tests => 85; BEGIN { use_ok("IkiWiki"); } %config=IkiWiki::defaultconfig(); @@ -42,19 +42,6 @@ ok($IkiWiki::depends_simple{foo2}{"baz"} & $IkiWiki::DEPEND_LINKS); ok($IkiWiki::depends_simple{foo2}{"baz"} & $IkiWiki::DEPEND_PRESENCE); ok(! ($IkiWiki::depends_simple{foo2}{"baz"} & $IkiWiki::DEPEND_CONTENT)); -# adding a pagespec that requires page metadata should cause a fallback to -# a content dependency -foreach my $spec ("* and ! link(bar)", "* or link(bar)", "unknownspec()", - "title(hi)", - "* or backlink(yo)", # this one could actually be acceptably be - # detected to not need a content dep .. in - # theory! - ) { - ok(add_depends("foo3", $spec, presence => 1)); - ok($IkiWiki::depends{foo3}{$spec} & $IkiWiki::DEPEND_CONTENT); - ok(! ($IkiWiki::depends{foo3}{$spec} & ($IkiWiki::DEPEND_PRESENCE | $IkiWiki::DEPEND_LINKS))); -} - # adding dep types to existing dependencies should merge the flags ok(add_depends("foo2", "baz")); ok($IkiWiki::depends_simple{foo2}{"baz"} & $IkiWiki::DEPEND_LINKS); @@ -66,3 +53,35 @@ ok(! ($IkiWiki::depends_simple{foo2}{"bar"} & $IkiWiki::DEPEND_CONTENT)); ok(add_depends("foo", "bar", links => 1)); # had only content before ok($IkiWiki::depends{foo}{"*"} & ($IkiWiki::DEPEND_CONTENT | $IkiWiki::DEPEND_LINKS)); ok(! ($IkiWiki::depends{foo}{"*"} & $IkiWiki::DEPEND_PRESENCE)); + +# adding a pagespec that requires page metadata should cause a fallback to +# a content dependency +foreach my $spec ("* and ! link(bar)", "* or link(bar)", "unknownspec()", + "title(hi)", + "* or unknown(yo)", # this one could actually be acceptably be + # detected to not need a content dep .. in + # theory! + ) { + ok(add_depends("foo3", $spec, presence => 1)); + ok($IkiWiki::depends{foo3}{$spec} & $IkiWiki::DEPEND_CONTENT); + ok(! ($IkiWiki::depends{foo3}{$spec} & ($IkiWiki::DEPEND_PRESENCE | $IkiWiki::DEPEND_LINKS))); + ok(add_depends("foo4", $spec, links => 1)); + ok($IkiWiki::depends{foo3}{$spec} & $IkiWiki::DEPEND_CONTENT); + ok(! ($IkiWiki::depends{foo3}{$spec} & ($IkiWiki::DEPEND_PRESENCE | $IkiWiki::DEPEND_LINKS))); +} + +# a pagespec with backlinks() in it is acceptable for a links dependency, +# but not a presence dependency +foreach my $spec ("index or (backlink(index) and !*.png)", "backlink(foo)") { + ok(add_depends("foo5", $spec, presence => 1)); + ok($IkiWiki::depends{foo5}{$spec} & $IkiWiki::DEPEND_CONTENT); + ok(! ($IkiWiki::depends{foo5}{$spec} & ($IkiWiki::DEPEND_PRESENCE | $IkiWiki::DEPEND_LINKS))); + ok(add_depends("foo6", $spec, links => 1)); + ok($IkiWiki::depends{foo6}{$spec} & $IkiWiki::DEPEND_LINKS); + ok(! ($IkiWiki::depends{foo6}{$spec} & ($IkiWiki::DEPEND_PRESENCE | $IkiWiki::DEPEND_CONTENT))); + # combining both ends up with a content+links dependency + ok(add_depends("foo7", $spec, presence => 1, links => 1)); + ok($IkiWiki::depends{foo7}{$spec} & $IkiWiki::DEPEND_CONTENT); + ok($IkiWiki::depends{foo7}{$spec} & $IkiWiki::DEPEND_LINKS); + ok(! ($IkiWiki::depends{foo7}{$spec} & $IkiWiki::DEPEND_PRESENCE)); +} -- cgit v1.2.3 From 03ae087b437ce7a91253fe256facf59b971ae3fc Mon Sep 17 00:00:00 2001 From: Joey Hess Date: Tue, 6 Oct 2009 18:44:59 -0400 Subject: support backlink() in pagespecs for links dependencies --- IkiWiki.pm | 43 ++++++++++++++++++++++++++++++++----------- 1 file changed, 32 insertions(+), 11 deletions(-) diff --git a/IkiWiki.pm b/IkiWiki.pm index b895e12fc..78592e6ad 100644 --- a/IkiWiki.pm +++ b/IkiWiki.pm @@ -1776,21 +1776,42 @@ sub add_depends ($$;@) { my $simple=$pagespec =~ /$config{wiki_file_regexp}/ && $pagespec !~ /[\s*?()!]/; - my $deptype=$DEPEND_CONTENT; + my $deptype=0; if (@_) { my %params=@_; - # Is the pagespec limited to terms that will continue - # to match pages as long as those pages exist? - my $limited=1; - while ($limited && $pagespec=~m/(\w+)\([^\)]*\)/g) { - $limited = $1 =~ /^(glob|internal|creation_month|creation_day|creation_year|created_before|created_after)$/; + if ($params{presence}) { + # Is the pagespec limited to terms that will continue + # to match pages as long as those pages exist? + my $presence_limited=1; + while ($presence_limited && $pagespec=~m/(\w+)\([^\)]*\)/g) { + $presence_limited = $1 =~ /^(glob|internal|creation_month|creation_day|creation_year|created_before|created_after)$/; + } + if ($presence_limited) { + $deptype=$deptype | $DEPEND_PRESENCE; + } + else { + $deptype=$deptype | $DEPEND_CONTENT; + } } - - $deptype=$deptype & ~$DEPEND_CONTENT | $DEPEND_PRESENCE - if $params{presence} && $limited; - $deptype=$deptype & ~$DEPEND_CONTENT | $DEPEND_LINKS - if $params{links} && $limited; + if ($params{links}) { + # Is the pagespec limited to terms that will continue + # to match pages as long as those pages exist and + # link to the same places? + my $links_limited=1; + while ($links_limited && $pagespec=~m/(\w+)\([^\)]*\)/g) { + $links_limited = $1 =~ /^(glob|internal|creation_month|creation_day|creation_year|created_before|created_after|backlink)$/; + } + if ($links_limited) { + $deptype=$deptype | $DEPEND_LINKS; + } + else { + $deptype=$deptype | $DEPEND_CONTENT; + } + } + } + else { + $deptype=$DEPEND_CONTENT; } if ($simple) { -- cgit v1.2.3 From ee56af29e189a7ca0f2a814a76d9086b6f41af9a Mon Sep 17 00:00:00 2001 From: Joey Hess Date: Tue, 6 Oct 2009 18:45:22 -0400 Subject: typo --- IkiWiki/Render.pm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/IkiWiki/Render.pm b/IkiWiki/Render.pm index 8f9cbf673..e28381c33 100644 --- a/IkiWiki/Render.pm +++ b/IkiWiki/Render.pm @@ -557,7 +557,7 @@ sub render_dependent ($$$$$$$) { my $in=sub { my $list=shift; my $type=shift; - foreach my $file ($list) { + foreach my $file (@$list) { next if $file eq $f; my $page=pagename($file); if ($sub->($page, location => $p)) { -- cgit v1.2.3 From e45e23a7f1018e1639b1ce1fdec1b2319050641d Mon Sep 17 00:00:00 2001 From: Joey Hess Date: Tue, 6 Oct 2009 19:03:23 -0400 Subject: oops!! --- IkiWiki.pm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/IkiWiki.pm b/IkiWiki.pm index 78592e6ad..7348ea2f7 100644 --- a/IkiWiki.pm +++ b/IkiWiki.pm @@ -1536,7 +1536,7 @@ sub loadindex () { }; } elsif (exists $d->{depends_simple}) { - $depends{$page}=$d->{depends_simple}; + $depends_simple{$page}=$d->{depends_simple}; } if (exists $d->{dependslist}) { # old format -- cgit v1.2.3 From 7a8b492bcce45123cef45ebe6f97cd70b38b9db7 Mon Sep 17 00:00:00 2001 From: Joey Hess Date: Tue, 6 Oct 2009 19:07:52 -0400 Subject: add_depends should default to content dependencies if unknown type specified --- IkiWiki.pm | 4 +--- t/add_depends.t | 7 ++++++- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/IkiWiki.pm b/IkiWiki.pm index 7348ea2f7..7b1d24c6a 100644 --- a/IkiWiki.pm +++ b/IkiWiki.pm @@ -1810,9 +1810,7 @@ sub add_depends ($$;@) { } } } - else { - $deptype=$DEPEND_CONTENT; - } + $deptype=$DEPEND_CONTENT unless $deptype; if ($simple) { $depends_simple{$page}{lc $pagespec} |= $deptype; diff --git a/t/add_depends.t b/t/add_depends.t index 68429b24a..2d686a17d 100755 --- a/t/add_depends.t +++ b/t/add_depends.t @@ -1,7 +1,7 @@ #!/usr/bin/perl use warnings; use strict; -use Test::More tests => 85; +use Test::More tests => 88; BEGIN { use_ok("IkiWiki"); } %config=IkiWiki::defaultconfig(); @@ -85,3 +85,8 @@ foreach my $spec ("index or (backlink(index) and !*.png)", "backlink(foo)") { ok($IkiWiki::depends{foo7}{$spec} & $IkiWiki::DEPEND_LINKS); ok(! ($IkiWiki::depends{foo7}{$spec} & $IkiWiki::DEPEND_PRESENCE)); } + +# content is the default if unknown types are entered +ok(add_depends("foo8", "*", presenCe => 1)); +ok($IkiWiki::depends{foo8}{"*"} & $IkiWiki::DEPEND_CONTENT); +ok(! ($IkiWiki::depends{foo8}{"*"} & ($IkiWiki::DEPEND_PRESENCE | $IkiWiki::DEPEND_LINKS))); -- cgit v1.2.3 From a5d825f28632655b608564893428ef9142dddb04 Mon Sep 17 00:00:00 2001 From: Joey Hess Date: Tue, 6 Oct 2009 19:24:17 -0400 Subject: linkmap: does need presence deps Otherwise, removal of a page with no links will not be noticed, since no links will change. --- IkiWiki/Plugin/linkmap.pm | 5 +++-- debian/changelog | 4 ++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/IkiWiki/Plugin/linkmap.pm b/IkiWiki/Plugin/linkmap.pm index b8b4cf40d..d7ba68da9 100644 --- a/IkiWiki/Plugin/linkmap.pm +++ b/IkiWiki/Plugin/linkmap.pm @@ -28,8 +28,9 @@ sub preprocess (@) { $params{pages}="*" unless defined $params{pages}; - # Needs to update whenever a relevant page's links change. - add_depends($params{page}, $params{pages}, links => 1); + # Needs to update whenever a relevant page is added, or removed, or + # its links change. + add_depends($params{page}, $params{pages}, presence => 1, links => 1); # Can't just return the linkmap here, since the htmlscrubber # scrubs out all tags (with good reason!) diff --git a/debian/changelog b/debian/changelog index a006d3177..dc6ee0a81 100644 --- a/debian/changelog +++ b/debian/changelog @@ -27,8 +27,8 @@ ikiwiki (3.14159266) UNRELEASED; urgency=low where if only a small set of pages were considered by orphans/pagestats, changes to links on other pages failed to cause an update. * linkmap: Use a combination of presence and link dependencies. - This makes the map be regenerated much less frequently, so larger - maps are more practical to use now. + This makes the map be regenerated much less frequently in many cases, + so larger maps are more practical to use now. * Transitive dependencies are now correctly supported. * Rebuild wikis on upgrade to this version to get improved dependency info. -- cgit v1.2.3 From 77598dfa9fccb668345198ea169cf7cf00b9845e Mon Sep 17 00:00:00 2001 From: Joey Hess Date: Tue, 6 Oct 2009 19:29:28 -0400 Subject: linkmap, pagestats: avoid using %links to get a list of pages When a page is deleted, it is removed from %pagesources, but not from %links. So use the former. --- IkiWiki/Plugin/linkmap.pm | 2 +- IkiWiki/Plugin/pagestats.pm | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/IkiWiki/Plugin/linkmap.pm b/IkiWiki/Plugin/linkmap.pm index d7ba68da9..3d20a6521 100644 --- a/IkiWiki/Plugin/linkmap.pm +++ b/IkiWiki/Plugin/linkmap.pm @@ -56,7 +56,7 @@ sub genmap ($) { # Get all the items to map. my %mapitems = (); - foreach my $item (keys %links) { + foreach my $item (keys %pagesources) { if (pagespec_match($item, $params{pages}, location => $params{page})) { $mapitems{$item}=urlto($item, $params{destpage}); } diff --git a/IkiWiki/Plugin/pagestats.pm b/IkiWiki/Plugin/pagestats.pm index 0765c1cfa..afe4eeaf2 100644 --- a/IkiWiki/Plugin/pagestats.pm +++ b/IkiWiki/Plugin/pagestats.pm @@ -45,7 +45,7 @@ sub preprocess (@) { my %counts; my $max = 0; - foreach my $page (pagespec_match_list([keys %links], + foreach my $page (pagespec_match_list([keys %pagesources], $params{pages}, location => $params{page})) { use IkiWiki::Render; -- cgit v1.2.3 From 136979fac670b6476069a63385d3e5e53643b68e Mon Sep 17 00:00:00 2001 From: Joey Hess Date: Wed, 7 Oct 2009 14:08:03 -0400 Subject: fix backlink new change detection code --- IkiWiki/Render.pm | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/IkiWiki/Render.pm b/IkiWiki/Render.pm index e28381c33..79935f323 100644 --- a/IkiWiki/Render.pm +++ b/IkiWiki/Render.pm @@ -494,7 +494,7 @@ sub calculate_changed_links ($$$) { my $target=bestlink($page, $l); if (! exists $oldlink_targets->{$page}{$l} || $target ne $oldlink_targets->{$page}{$l}) { - $backlinkchanged{$l}=1; + $backlinkchanged{$target}=1; $linkchangers{lc($page)}=1; } delete $oldlink_targets->{$page}{$l}; @@ -502,7 +502,7 @@ sub calculate_changed_links ($$$) { } if (exists $oldlink_targets->{$page} && %{$oldlink_targets->{$page}}) { - foreach my $target (keys %{$oldlink_targets->{$page}}) { + foreach my $target (values %{$oldlink_targets->{$page}}) { $backlinkchanged{$target}=1; } $linkchangers{lc($page)}=1; -- cgit v1.2.3 From 8fa0cfced9a3d0f79cbf7867e354530d11f9f211 Mon Sep 17 00:00:00 2001 From: Joey Hess Date: Wed, 7 Oct 2009 14:11:35 -0400 Subject: remove test case for closed bug --- doc/bugs/Inline_doesn__39__t_wikilink_to_pages.mdwn | 4 ---- 1 file changed, 4 deletions(-) diff --git a/doc/bugs/Inline_doesn__39__t_wikilink_to_pages.mdwn b/doc/bugs/Inline_doesn__39__t_wikilink_to_pages.mdwn index 32f9f1245..13b80b436 100644 --- a/doc/bugs/Inline_doesn__39__t_wikilink_to_pages.mdwn +++ b/doc/bugs/Inline_doesn__39__t_wikilink_to_pages.mdwn @@ -2,10 +2,6 @@ It seems that the [[ikiwiki/directive/inline]] directive doesn't generate wikili \[[!inline pages="bugs/* and !*/discussion and backlink(bugs)" feeds=no postform=no archive=yes show="10"]] -But here it is: - -[[!inline pages="bugs/* and !*/discussion and backlink(bugs)" feeds=no postform=no archive=yes show="10"]] - and note that it only included the 'normal' wikilinks (and also note that this page is not marked done even though the done page is inlined). One might also wonder if inline would make this page link to any internal links on those inlined pages too, but I think that would be overkill. -- cgit v1.2.3 From c72fda7d695142cc29ac986125234140f6414d97 Mon Sep 17 00:00:00 2001 From: Joey Hess Date: Wed, 7 Oct 2009 19:40:44 -0400 Subject: make success and failreason objects carry an influences hash The hash will be used used to record a set of pages that influenced the result of a pagespec match. The influences are merged together when boolean and/or are encountered in a pagespec. That means using a non-short-circuiting OR operator. And so I use & and | when translating pagespecs, since those bitwise operators can be overloaded. ("and" and "or" cannot, apparently). --- IkiWiki.pm | 34 +++++++++++++++++++--------------- t/pagespec_match.t | 6 +++++- 2 files changed, 24 insertions(+), 16 deletions(-) diff --git a/IkiWiki.pm b/IkiWiki.pm index 7b1d24c6a..73d2a9763 100644 --- a/IkiWiki.pm +++ b/IkiWiki.pm @@ -1926,10 +1926,10 @@ sub pagespec_translate ($) { }gx) { my $word=$1; if (lc $word eq 'and') { - $code.=' &&'; + $code.=' &'; } elsif (lc $word eq 'or') { - $code.=' ||'; + $code.=' |'; } elsif ($word eq "(" || $word eq ")" || $word eq "!") { $code.=' '.$word; @@ -2015,36 +2015,40 @@ sub glob2re ($) { package IkiWiki::FailReason; use overload ( - '""' => sub { ${$_[0]} }, + '""' => sub { $_[0][0] }, '0+' => sub { 0 }, '!' => sub { bless $_[0], 'IkiWiki::SuccessReason'}, + '&' => sub { $_[0][1]={%{$_[0][1]}, %{$_[1][1]}}; $_[0] }, + '|' => sub { $_[1][1]={%{$_[0][1]}, %{$_[1][1]}}; $_[1] }, fallback => 1, ); -sub new { - my $class = shift; - my $value = shift; - return bless \$value, $class; -} - -package IkiWiki::ErrorReason; - -our @ISA = 'IkiWiki::FailReason'; +our @ISA = 'IkiWiki::SuccessReason'; package IkiWiki::SuccessReason; use overload ( - '""' => sub { ${$_[0]} }, + '""' => sub { $_[0][0] }, '0+' => sub { 1 }, '!' => sub { bless $_[0], 'IkiWiki::FailReason'}, + '&' => sub { $_[1][1]={%{$_[0][1]}, %{$_[1][1]}}; $_[1] }, + '|' => sub { $_[0][1]={%{$_[0][1]}, %{$_[1][1]}}; $_[0] }, fallback => 1, ); sub new { my $class = shift; my $value = shift; - return bless \$value, $class; -}; + return bless [$value, {@_}], $class; +} + +sub influences { + return keys %{$_[0][1]}; +} + +package IkiWiki::ErrorReason; + +our @ISA = 'IkiWiki::FailReason'; package IkiWiki::PageSpec; diff --git a/t/pagespec_match.t b/t/pagespec_match.t index 64408f489..a1fcba7c8 100755 --- a/t/pagespec_match.t +++ b/t/pagespec_match.t @@ -1,7 +1,7 @@ #!/usr/bin/perl use warnings; use strict; -use Test::More tests => 54; +use Test::More tests => 56; BEGIN { use_ok("IkiWiki"); } @@ -88,3 +88,7 @@ ok(! pagespec_match("foo", "no_such_function(foo)"), "foo"); my $ret=pagespec_match("foo", "(invalid"); ok(! $ret, "syntax error"); ok($ret =~ /syntax error/, "error message"); + +my $ret=pagespec_match("foo", "bar or foo"); +ok($ret, "simple match"); +is($ret, "foo matches foo", "stringified return"); -- cgit v1.2.3 From 4002d7c1a4657e769b036c6e76106991ec5c3897 Mon Sep 17 00:00:00 2001 From: Joey Hess Date: Wed, 7 Oct 2009 20:31:13 -0400 Subject: add influence info to match_* Also update docs, test suite. --- IkiWiki.pm | 24 ++++++++++++------------ IkiWiki/Plugin/meta.pm | 8 ++++---- debian/changelog | 2 ++ doc/plugins/write.mdwn | 7 +++++++ t/pagespec_match.t | 15 +++++++++++++-- 5 files changed, 38 insertions(+), 18 deletions(-) diff --git a/IkiWiki.pm b/IkiWiki.pm index 73d2a9763..9c386e154 100644 --- a/IkiWiki.pm +++ b/IkiWiki.pm @@ -2039,7 +2039,7 @@ use overload ( sub new { my $class = shift; my $value = shift; - return bless [$value, {@_}], $class; + return bless [$value, {map { $_ => 1 } @_}], $class; } sub influences { @@ -2099,23 +2099,23 @@ sub match_link ($$;@) { my $from=exists $params{location} ? $params{location} : ''; my $links = $IkiWiki::links{$page}; - return IkiWiki::FailReason->new("$page has no links") unless $links && @{$links}; + return IkiWiki::FailReason->new("$page has no links", $link) unless $links && @{$links}; my $bestlink = IkiWiki::bestlink($from, $link); foreach my $p (@{$links}) { if (length $bestlink) { - return IkiWiki::SuccessReason->new("$page links to $link") + return IkiWiki::SuccessReason->new("$page links to $link", $page) if $bestlink eq IkiWiki::bestlink($page, $p); } else { - return IkiWiki::SuccessReason->new("$page links to page $p matching $link") + return IkiWiki::SuccessReason->new("$page links to page $p matching $link", $page) if match_glob($p, $link, %params); my ($p_rel)=$p=~/^\/?(.*)/; $link=~s/^\///; - return IkiWiki::SuccessReason->new("$page links to page $p_rel matching $link") + return IkiWiki::SuccessReason->new("$page links to page $p_rel matching $link", $page) if match_glob($p_rel, $link, %params); } } - return IkiWiki::FailReason->new("$page does not link to $link"); + return IkiWiki::FailReason->new("$page does not link to $link", $page); } sub match_backlink ($$;@) { @@ -2131,14 +2131,14 @@ sub match_created_before ($$;@) { if (exists $IkiWiki::pagectime{$testpage}) { if ($IkiWiki::pagectime{$page} < $IkiWiki::pagectime{$testpage}) { - return IkiWiki::SuccessReason->new("$page created before $testpage"); + return IkiWiki::SuccessReason->new("$page created before $testpage", $testpage); } else { - return IkiWiki::FailReason->new("$page not created before $testpage"); + return IkiWiki::FailReason->new("$page not created before $testpage", $testpage); } } else { - return IkiWiki::ErrorReason->new("$testpage does not exist"); + return IkiWiki::ErrorReason->new("$testpage does not exist", $testpage); } } @@ -2151,14 +2151,14 @@ sub match_created_after ($$;@) { if (exists $IkiWiki::pagectime{$testpage}) { if ($IkiWiki::pagectime{$page} > $IkiWiki::pagectime{$testpage}) { - return IkiWiki::SuccessReason->new("$page created after $testpage"); + return IkiWiki::SuccessReason->new("$page created after $testpage", $testpage); } else { - return IkiWiki::FailReason->new("$page not created after $testpage"); + return IkiWiki::FailReason->new("$page not created after $testpage", $testpage); } } else { - return IkiWiki::ErrorReason->new("$testpage does not exist"); + return IkiWiki::ErrorReason->new("$testpage does not exist", $testpage); } } diff --git a/IkiWiki/Plugin/meta.pm b/IkiWiki/Plugin/meta.pm index 9b041a748..a8ee5bc85 100644 --- a/IkiWiki/Plugin/meta.pm +++ b/IkiWiki/Plugin/meta.pm @@ -291,21 +291,21 @@ sub match { if (defined $val) { if ($val=~/^$re$/i) { - return IkiWiki::SuccessReason->new("$re matches $field of $page"); + return IkiWiki::SuccessReason->new("$re matches $field of $page", $page); } else { - return IkiWiki::FailReason->new("$re does not match $field of $page"); + return IkiWiki::FailReason->new("$re does not match $field of $page", $page); } } else { - return IkiWiki::FailReason->new("$page does not have a $field"); + return IkiWiki::FailReason->new("$page does not have a $field", $page); } } package IkiWiki::PageSpec; sub match_title ($$;@) { - IkiWiki::Plugin::meta::match("title", @_); + IkiWiki::Plugin::meta::match("title", @_); } sub match_author ($$;@) { diff --git a/debian/changelog b/debian/changelog index dc6ee0a81..565a0cffa 100644 --- a/debian/changelog +++ b/debian/changelog @@ -32,6 +32,8 @@ ikiwiki (3.14159266) UNRELEASED; urgency=low * Transitive dependencies are now correctly supported. * Rebuild wikis on upgrade to this version to get improved dependency info. + * Plugins providing PageSpec `match_*` functions should pass additional + influence information when creating result objects. -- Joey Hess Sun, 27 Sep 2009 17:40:03 -0400 diff --git a/doc/plugins/write.mdwn b/doc/plugins/write.mdwn index 8e8c3311e..6b47033e5 100644 --- a/doc/plugins/write.mdwn +++ b/doc/plugins/write.mdwn @@ -982,6 +982,13 @@ 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. +When constructing these objects, you should also include a list 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. + ### Setup plugins The ikiwiki setup file is loaded using a pluggable mechanism. If you look diff --git a/t/pagespec_match.t b/t/pagespec_match.t index a1fcba7c8..f73bfdfe1 100755 --- a/t/pagespec_match.t +++ b/t/pagespec_match.t @@ -1,7 +1,7 @@ #!/usr/bin/perl use warnings; use strict; -use Test::More tests => 56; +use Test::More tests => 61; BEGIN { use_ok("IkiWiki"); } @@ -89,6 +89,17 @@ my $ret=pagespec_match("foo", "(invalid"); ok(! $ret, "syntax error"); ok($ret =~ /syntax error/, "error message"); -my $ret=pagespec_match("foo", "bar or foo"); +$ret=pagespec_match("foo", "bar or foo"); ok($ret, "simple match"); is($ret, "foo matches foo", "stringified return"); + +$ret=pagespec_match("foo", "link(bar)"); +is(join(",", $ret->influences), 'foo', "link is influenced by the page with the link"); +$ret=pagespec_match("bar", "backlink(foo)"); +is(join(",", $ret->influences), 'foo', "backlink is influenced by the page with the link"); +$ret=pagespec_match("bar", "backlink(foo)"); +is(join(",", $ret->influences), 'foo', "backlink is influenced by the page with the link"); +$ret=pagespec_match("bar", "created_before(foo)"); +is(join(",", $ret->influences), 'foo', "created_before is influenced by the comparison page"); +$ret=pagespec_match("bar", "created_after(foo)"); +is(join(",", $ret->influences), 'foo', "created_after is influenced by the comparison page"); -- cgit v1.2.3 From 54fb82a5a47078f6865ed5bf7d7c09db4bf34e22 Mon Sep 17 00:00:00 2001 From: Joey Hess Date: Wed, 7 Oct 2009 20:35:26 -0400 Subject: more influences tests --- t/pagespec_match.t | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/t/pagespec_match.t b/t/pagespec_match.t index f73bfdfe1..1a0db1cef 100755 --- a/t/pagespec_match.t +++ b/t/pagespec_match.t @@ -1,7 +1,7 @@ #!/usr/bin/perl use warnings; use strict; -use Test::More tests => 61; +use Test::More tests => 64; BEGIN { use_ok("IkiWiki"); } @@ -103,3 +103,9 @@ $ret=pagespec_match("bar", "created_before(foo)"); is(join(",", $ret->influences), 'foo', "created_before is influenced by the comparison page"); $ret=pagespec_match("bar", "created_after(foo)"); is(join(",", $ret->influences), 'foo', "created_after is influenced by the comparison page"); +$ret=pagespec_match("bar", "link(quux) and created_after(foo)"); +is(join(",", sort $ret->influences), 'foo,quux', "influences add up over AND"); +$ret=pagespec_match("bar", "link(quux) and created_after(foo)"); +is(join(",", sort $ret->influences), 'foo,quux', "influences add up over OR"); +$ret=pagespec_match("bar", "!link(quux) and !created_after(foo)"); +is(join(",", sort $ret->influences), 'foo,quux', "influences unaffected by negation"); -- cgit v1.2.3 From bb389a5ae25461ed20e2d28b18ea8b08f5f36473 Mon Sep 17 00:00:00 2001 From: Joey Hess Date: Wed, 7 Oct 2009 21:13:10 -0400 Subject: convert add_depends to use influences No more horrible special-case pagespec parsing. OTOH, matching over all pages to determine influences is a lot of work. --- IkiWiki.pm | 52 +++++++++++----------------------- t/add_depends.t | 86 ++++++++++++++++++++++++++++++--------------------------- 2 files changed, 62 insertions(+), 76 deletions(-) diff --git a/IkiWiki.pm b/IkiWiki.pm index 9c386e154..7adc63139 100644 --- a/IkiWiki.pm +++ b/IkiWiki.pm @@ -1772,52 +1772,32 @@ sub add_depends ($$;@) { my $page=shift; my $pagespec=shift; - # Is the pagespec a simple page name? - my $simple=$pagespec =~ /$config{wiki_file_regexp}/ && - $pagespec !~ /[\s*?()!]/; - my $deptype=0; if (@_) { my %params=@_; - if ($params{presence}) { - # Is the pagespec limited to terms that will continue - # to match pages as long as those pages exist? - my $presence_limited=1; - while ($presence_limited && $pagespec=~m/(\w+)\([^\)]*\)/g) { - $presence_limited = $1 =~ /^(glob|internal|creation_month|creation_day|creation_year|created_before|created_after)$/; - } - if ($presence_limited) { - $deptype=$deptype | $DEPEND_PRESENCE; - } - else { - $deptype=$deptype | $DEPEND_CONTENT; - } - } - if ($params{links}) { - # Is the pagespec limited to terms that will continue - # to match pages as long as those pages exist and - # link to the same places? - my $links_limited=1; - while ($links_limited && $pagespec=~m/(\w+)\([^\)]*\)/g) { - $links_limited = $1 =~ /^(glob|internal|creation_month|creation_day|creation_year|created_before|created_after|backlink)$/; - } - if ($links_limited) { - $deptype=$deptype | $DEPEND_LINKS; - } - else { - $deptype=$deptype | $DEPEND_CONTENT; - } - } + $deptype=$deptype | $DEPEND_PRESENCE if $params{presence}; + $deptype=$deptype | $DEPEND_LINKS if $params{links}; } $deptype=$DEPEND_CONTENT unless $deptype; - if ($simple) { + # Is the pagespec a simple page name? + if ($pagespec =~ /$config{wiki_file_regexp}/ && + $pagespec !~ /[\s*?()!]/) { $depends_simple{$page}{lc $pagespec} |= $deptype; return 1; } - return unless pagespec_valid($pagespec); + # Analyse the pagespec, and match it against all pages + # to get a list of influences, and add explicit + # content dependencies for those. + my $sub=pagespec_translate($pagespec); + return if $@; + foreach my $p (keys %pagesources) { + my $r=$sub->($p, location => $page ); + map { $depends_simple{$page}{lc $_} |= $DEPEND_CONTENT } $r->influences + if $r; + } $depends{$page}{$pagespec} |= $deptype; return 1; @@ -2099,7 +2079,7 @@ sub match_link ($$;@) { my $from=exists $params{location} ? $params{location} : ''; my $links = $IkiWiki::links{$page}; - return IkiWiki::FailReason->new("$page has no links", $link) unless $links && @{$links}; + return IkiWiki::FailReason->new("$page has no links", $page) unless $links && @{$links}; my $bestlink = IkiWiki::bestlink($from, $link); foreach my $p (@{$links}) { if (length $bestlink) { diff --git a/t/add_depends.t b/t/add_depends.t index 2d686a17d..d49aa74ce 100755 --- a/t/add_depends.t +++ b/t/add_depends.t @@ -8,25 +8,27 @@ BEGIN { use_ok("IkiWiki"); } $config{srcdir}=$config{destdir}="/dev/null"; IkiWiki::checkconfig(); +$pagesources{"foo$_"}="foo$_.mdwn" for 0..9; + # avoids adding an unparseable pagespec -ok(! add_depends("foo", "foo and (bar")); -ok(! add_depends("foo", "foo another")); +ok(! add_depends("foo0", "foo and (bar")); +ok(! add_depends("foo0", "foo another")); # simple and not-so-simple dependencies split -ok(add_depends("foo", "*")); -ok(add_depends("foo", "bar")); -ok(add_depends("foo", "BAZ")); -ok(exists $IkiWiki::depends_simple{foo}{"bar"}); -ok(exists $IkiWiki::depends_simple{foo}{"baz"}); # lowercase -ok(! exists $IkiWiki::depends_simple{foo}{"*"}); -ok(! exists $IkiWiki::depends{foo}{"bar"}); -ok(! exists $IkiWiki::depends{foo}{"baz"}); +ok(add_depends("foo0", "*")); +ok(add_depends("foo0", "bar")); +ok(add_depends("foo0", "BAZ")); +ok(exists $IkiWiki::depends_simple{foo0}{"bar"}); +ok(exists $IkiWiki::depends_simple{foo0}{"baz"}); # lowercase +ok(! exists $IkiWiki::depends_simple{foo0}{"*"}); +ok(! exists $IkiWiki::depends{foo0}{"bar"}); +ok(! exists $IkiWiki::depends{foo0}{"baz"}); # default dependencies are content dependencies -ok($IkiWiki::depends{foo}{"*"} & $IkiWiki::DEPEND_CONTENT); -ok(! ($IkiWiki::depends{foo}{"*"} & ($IkiWiki::DEPEND_PRESENCE | $IkiWiki::DEPEND_LINKS))); -ok($IkiWiki::depends_simple{foo}{"bar"} & $IkiWiki::DEPEND_CONTENT); -ok(! ($IkiWiki::depends_simple{foo}{"bar"} & ($IkiWiki::DEPEND_PRESENCE | $IkiWiki::DEPEND_LINKS))); +ok($IkiWiki::depends{foo0}{"*"} & $IkiWiki::DEPEND_CONTENT); +ok(! ($IkiWiki::depends{foo0}{"*"} & ($IkiWiki::DEPEND_PRESENCE | $IkiWiki::DEPEND_LINKS))); +ok($IkiWiki::depends_simple{foo0}{"bar"} & $IkiWiki::DEPEND_CONTENT); +ok(! ($IkiWiki::depends_simple{foo0}{"bar"} & ($IkiWiki::DEPEND_PRESENCE | $IkiWiki::DEPEND_LINKS))); # adding other dep types standalone ok(add_depends("foo2", "*", presence => 1)); @@ -50,43 +52,47 @@ ok(($IkiWiki::depends_simple{foo2}{"baz"} & $IkiWiki::DEPEND_CONTENT)); ok(add_depends("foo2", "bar", presence => 1)); # had only links before ok($IkiWiki::depends_simple{foo2}{"bar"} & ($IkiWiki::DEPEND_LINKS | $IkiWiki::DEPEND_PRESENCE)); ok(! ($IkiWiki::depends_simple{foo2}{"bar"} & $IkiWiki::DEPEND_CONTENT)); -ok(add_depends("foo", "bar", links => 1)); # had only content before -ok($IkiWiki::depends{foo}{"*"} & ($IkiWiki::DEPEND_CONTENT | $IkiWiki::DEPEND_LINKS)); -ok(! ($IkiWiki::depends{foo}{"*"} & $IkiWiki::DEPEND_PRESENCE)); +ok(add_depends("foo0", "bar", links => 1)); # had only content before +ok($IkiWiki::depends{foo0}{"*"} & ($IkiWiki::DEPEND_CONTENT | $IkiWiki::DEPEND_LINKS)); +ok(! ($IkiWiki::depends{foo0}{"*"} & $IkiWiki::DEPEND_PRESENCE)); -# adding a pagespec that requires page metadata should cause a fallback to -# a content dependency -foreach my $spec ("* and ! link(bar)", "* or link(bar)", "unknownspec()", - "title(hi)", - "* or unknown(yo)", # this one could actually be acceptably be - # detected to not need a content dep .. in - # theory! - ) { +# Adding a pagespec that requires page metadata should add the influence +# as an explicit content dependency. +$links{foo0}=$links{foo9}=[qw{bar baz}]; +foreach my $spec ("* and ! link(bar)", "* or link(bar)") { ok(add_depends("foo3", $spec, presence => 1)); - ok($IkiWiki::depends{foo3}{$spec} & $IkiWiki::DEPEND_CONTENT); - ok(! ($IkiWiki::depends{foo3}{$spec} & ($IkiWiki::DEPEND_PRESENCE | $IkiWiki::DEPEND_LINKS))); + ok($IkiWiki::depends{foo3}{$spec} & $IkiWiki::DEPEND_PRESENCE); + ok(! ($IkiWiki::depends{foo3}{$spec} & ($IkiWiki::DEPEND_CONTENT | $IkiWiki::DEPEND_LINKS))); + ok($IkiWiki::depends_simple{foo3}{foo3} == $IkiWiki::DEPEND_CONTENT); ok(add_depends("foo4", $spec, links => 1)); - ok($IkiWiki::depends{foo3}{$spec} & $IkiWiki::DEPEND_CONTENT); - ok(! ($IkiWiki::depends{foo3}{$spec} & ($IkiWiki::DEPEND_PRESENCE | $IkiWiki::DEPEND_LINKS))); + ok($IkiWiki::depends{foo4}{$spec} & $IkiWiki::DEPEND_LINKS); + ok(! ($IkiWiki::depends{foo4}{$spec} & ($IkiWiki::DEPEND_CONTENT | $IkiWiki::DEPEND_PRESENCE))); + ok($IkiWiki::depends_simple{foo4}{foo4} == $IkiWiki::DEPEND_CONTENT); } -# a pagespec with backlinks() in it is acceptable for a links dependency, -# but not a presence dependency -foreach my $spec ("index or (backlink(index) and !*.png)", "backlink(foo)") { +# a pagespec with backlinks() will add as an influence the page with the links +$links{foo0}=[qw{foo5 foo7}]; +foreach my $spec ("bugs or (backlink(foo0) and !*.png)", "backlink(foo)") { ok(add_depends("foo5", $spec, presence => 1)); - ok($IkiWiki::depends{foo5}{$spec} & $IkiWiki::DEPEND_CONTENT); - ok(! ($IkiWiki::depends{foo5}{$spec} & ($IkiWiki::DEPEND_PRESENCE | $IkiWiki::DEPEND_LINKS))); + ok($IkiWiki::depends{foo5}{$spec} & $IkiWiki::DEPEND_PRESENCE); + ok(! ($IkiWiki::depends{foo5}{$spec} & ($IkiWiki::DEPEND_CONTENT | $IkiWiki::DEPEND_LINKS))); + ok($IkiWiki::depends_simple{foo5}{foo0} == $IkiWiki::DEPEND_CONTENT); ok(add_depends("foo6", $spec, links => 1)); ok($IkiWiki::depends{foo6}{$spec} & $IkiWiki::DEPEND_LINKS); ok(! ($IkiWiki::depends{foo6}{$spec} & ($IkiWiki::DEPEND_PRESENCE | $IkiWiki::DEPEND_CONTENT))); - # combining both ends up with a content+links dependency + ok($IkiWiki::depends_simple{foo5}{foo0} == $IkiWiki::DEPEND_CONTENT); ok(add_depends("foo7", $spec, presence => 1, links => 1)); - ok($IkiWiki::depends{foo7}{$spec} & $IkiWiki::DEPEND_CONTENT); + ok($IkiWiki::depends{foo7}{$spec} & $IkiWiki::DEPEND_PRESENCE); ok($IkiWiki::depends{foo7}{$spec} & $IkiWiki::DEPEND_LINKS); - ok(! ($IkiWiki::depends{foo7}{$spec} & $IkiWiki::DEPEND_PRESENCE)); + ok(! ($IkiWiki::depends{foo7}{$spec} & $IkiWiki::DEPEND_CONTENT)); + ok($IkiWiki::depends_simple{foo7}{foo0} == $IkiWiki::DEPEND_CONTENT); + ok(add_depends("foo8", $spec)); + ok($IkiWiki::depends{foo8}{$spec} & $IkiWiki::DEPEND_CONTENT); + ok(! ($IkiWiki::depends{foo8}{$spec} & ($IkiWiki::DEPEND_PRESENCE | $IkiWiki::DEPEND_LINKS))); + ok($IkiWiki::depends_simple{foo8}{foo0} == $IkiWiki::DEPEND_CONTENT); } # content is the default if unknown types are entered -ok(add_depends("foo8", "*", presenCe => 1)); -ok($IkiWiki::depends{foo8}{"*"} & $IkiWiki::DEPEND_CONTENT); -ok(! ($IkiWiki::depends{foo8}{"*"} & ($IkiWiki::DEPEND_PRESENCE | $IkiWiki::DEPEND_LINKS))); +ok(add_depends("foo9", "*", presenCe => 1)); +ok($IkiWiki::depends{foo9}{"*"} & $IkiWiki::DEPEND_CONTENT); +ok(! ($IkiWiki::depends{foo9}{"*"} & ($IkiWiki::DEPEND_PRESENCE | $IkiWiki::DEPEND_LINKS))); -- cgit v1.2.3 From 5f9860e65c65aa769f11e550e63cc164b1519710 Mon Sep 17 00:00:00 2001 From: Joey Hess Date: Wed, 7 Oct 2009 21:48:03 -0400 Subject: add type info to influence information --- IkiWiki.pm | 49 ++++++++++++++++++++++++++++++------------------- IkiWiki/Plugin/meta.pm | 6 +++--- doc/plugins/write.mdwn | 6 +++--- docwiki.setup | 2 +- t/add_depends.t | 14 +++++++------- t/pagespec_match.t | 32 ++++++++++++++++---------------- 6 files changed, 60 insertions(+), 49 deletions(-) diff --git a/IkiWiki.pm b/IkiWiki.pm index 7adc63139..39a43ddbe 100644 --- a/IkiWiki.pm +++ b/IkiWiki.pm @@ -1795,8 +1795,10 @@ sub add_depends ($$;@) { return if $@; foreach my $p (keys %pagesources) { my $r=$sub->($p, location => $page ); - map { $depends_simple{$page}{lc $_} |= $DEPEND_CONTENT } $r->influences - if $r; + my %i=$r->influences; + foreach my $i (keys %i) { + $depends_simple{$page}{lc $i} |= $i{$i}; + } } $depends{$page}{$pagespec} |= $deptype; @@ -1998,8 +2000,8 @@ use overload ( '""' => sub { $_[0][0] }, '0+' => sub { 0 }, '!' => sub { bless $_[0], 'IkiWiki::SuccessReason'}, - '&' => sub { $_[0][1]={%{$_[0][1]}, %{$_[1][1]}}; $_[0] }, - '|' => sub { $_[1][1]={%{$_[0][1]}, %{$_[1][1]}}; $_[1] }, + '&' => sub { $_[0]->merge_influences($_[1]); $_[0] }, + '|' => sub { $_[1]->merge_influences($_[0]); $_[1] }, fallback => 1, ); @@ -2011,19 +2013,27 @@ use overload ( '""' => sub { $_[0][0] }, '0+' => sub { 1 }, '!' => sub { bless $_[0], 'IkiWiki::FailReason'}, - '&' => sub { $_[1][1]={%{$_[0][1]}, %{$_[1][1]}}; $_[1] }, - '|' => sub { $_[0][1]={%{$_[0][1]}, %{$_[1][1]}}; $_[0] }, + '&' => sub { $_[1]->merge_influences($_[0]); $_[1] }, + '|' => sub { $_[0]->merge_influences($_[1]); $_[0] }, fallback => 1, ); sub new { my $class = shift; my $value = shift; - return bless [$value, {map { $_ => 1 } @_}], $class; + return bless [$value, {@_}], $class; } sub influences { - return keys %{$_[0][1]}; + return %{$_[0][1]}; +} + +sub merge_influences { + my $this=shift; + my $other=shift; + foreach my $influence (keys %{$other->[1]}) { + $this->[1]{$influence} |= $other->[1]{$influence}; + } } package IkiWiki::ErrorReason; @@ -2079,23 +2089,24 @@ sub match_link ($$;@) { my $from=exists $params{location} ? $params{location} : ''; my $links = $IkiWiki::links{$page}; - return IkiWiki::FailReason->new("$page has no links", $page) unless $links && @{$links}; + return IkiWiki::FailReason->new("$page has no links", $page => $IkiWiki::DEPEND_LINKS) + unless $links && @{$links}; my $bestlink = IkiWiki::bestlink($from, $link); foreach my $p (@{$links}) { if (length $bestlink) { - return IkiWiki::SuccessReason->new("$page links to $link", $page) + return IkiWiki::SuccessReason->new("$page links to $link", $page => $IkiWiki::DEPEND_LINKS) if $bestlink eq IkiWiki::bestlink($page, $p); } else { - return IkiWiki::SuccessReason->new("$page links to page $p matching $link", $page) + return IkiWiki::SuccessReason->new("$page links to page $p matching $link", $page => $IkiWiki::DEPEND_LINKS) if match_glob($p, $link, %params); my ($p_rel)=$p=~/^\/?(.*)/; $link=~s/^\///; - return IkiWiki::SuccessReason->new("$page links to page $p_rel matching $link", $page) + return IkiWiki::SuccessReason->new("$page links to page $p_rel matching $link", $page => $IkiWiki::DEPEND_LINKS) if match_glob($p_rel, $link, %params); } } - return IkiWiki::FailReason->new("$page does not link to $link", $page); + return IkiWiki::FailReason->new("$page does not link to $link", $page => $IkiWiki::DEPEND_LINKS); } sub match_backlink ($$;@) { @@ -2111,14 +2122,14 @@ sub match_created_before ($$;@) { if (exists $IkiWiki::pagectime{$testpage}) { if ($IkiWiki::pagectime{$page} < $IkiWiki::pagectime{$testpage}) { - return IkiWiki::SuccessReason->new("$page created before $testpage", $testpage); + return IkiWiki::SuccessReason->new("$page created before $testpage", $testpage => $IkiWiki::DEPEND_PRESENCE); } else { - return IkiWiki::FailReason->new("$page not created before $testpage", $testpage); + return IkiWiki::FailReason->new("$page not created before $testpage", $testpage => $IkiWiki::DEPEND_PRESENCE); } } else { - return IkiWiki::ErrorReason->new("$testpage does not exist", $testpage); + return IkiWiki::ErrorReason->new("$testpage does not exist", $testpage => $IkiWiki::DEPEND_PRESENCE); } } @@ -2131,14 +2142,14 @@ sub match_created_after ($$;@) { if (exists $IkiWiki::pagectime{$testpage}) { if ($IkiWiki::pagectime{$page} > $IkiWiki::pagectime{$testpage}) { - return IkiWiki::SuccessReason->new("$page created after $testpage", $testpage); + return IkiWiki::SuccessReason->new("$page created after $testpage", $testpage => $IkiWiki::DEPEND_PRESENCE); } else { - return IkiWiki::FailReason->new("$page not created after $testpage", $testpage); + return IkiWiki::FailReason->new("$page not created after $testpage", $testpage => $IkiWiki::DEPEND_PRESENCE); } } else { - return IkiWiki::ErrorReason->new("$testpage does not exist", $testpage); + return IkiWiki::ErrorReason->new("$testpage does not exist", $testpage => $IkiWiki::DEPEND_PRESENCE); } } diff --git a/IkiWiki/Plugin/meta.pm b/IkiWiki/Plugin/meta.pm index a8ee5bc85..c160e7eba 100644 --- a/IkiWiki/Plugin/meta.pm +++ b/IkiWiki/Plugin/meta.pm @@ -291,14 +291,14 @@ sub match { if (defined $val) { if ($val=~/^$re$/i) { - return IkiWiki::SuccessReason->new("$re matches $field of $page", $page); + return IkiWiki::SuccessReason->new("$re matches $field of $page", $page => $IkiWiki::DEPEND_CONTENT); } else { - return IkiWiki::FailReason->new("$re does not match $field of $page", $page); + return IkiWiki::FailReason->new("$re does not match $field of $page", $page => $IkiWiki::DEPEND_CONTENT); } } else { - return IkiWiki::FailReason->new("$page does not have a $field", $page); + return IkiWiki::FailReason->new("$page does not have a $field", $page => $IkiWiki::DEPEND_CONTENT); } } diff --git a/doc/plugins/write.mdwn b/doc/plugins/write.mdwn index 6b47033e5..232430079 100644 --- a/doc/plugins/write.mdwn +++ b/doc/plugins/write.mdwn @@ -982,9 +982,9 @@ 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. -When constructing these objects, you should also include a list 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; +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. diff --git a/docwiki.setup b/docwiki.setup index 52421e501..41c07f024 100644 --- a/docwiki.setup +++ b/docwiki.setup @@ -16,5 +16,5 @@ use IkiWiki::Setup::Standard { userdir => "users", usedirs => 0, prefix_directives => 1, - add_plugins => [qw{goodstuff version haiku polygen fortune}], + add_plugins => [qw{linkmap goodstuff version haiku polygen fortune}], } diff --git a/t/add_depends.t b/t/add_depends.t index d49aa74ce..9f426187b 100755 --- a/t/add_depends.t +++ b/t/add_depends.t @@ -57,17 +57,17 @@ ok($IkiWiki::depends{foo0}{"*"} & ($IkiWiki::DEPEND_CONTENT | $IkiWiki::DEPEND_L ok(! ($IkiWiki::depends{foo0}{"*"} & $IkiWiki::DEPEND_PRESENCE)); # Adding a pagespec that requires page metadata should add the influence -# as an explicit content dependency. +# as an explicit dependency. In the case of a link, a links dependency. $links{foo0}=$links{foo9}=[qw{bar baz}]; foreach my $spec ("* and ! link(bar)", "* or link(bar)") { ok(add_depends("foo3", $spec, presence => 1)); ok($IkiWiki::depends{foo3}{$spec} & $IkiWiki::DEPEND_PRESENCE); ok(! ($IkiWiki::depends{foo3}{$spec} & ($IkiWiki::DEPEND_CONTENT | $IkiWiki::DEPEND_LINKS))); - ok($IkiWiki::depends_simple{foo3}{foo3} == $IkiWiki::DEPEND_CONTENT); + ok($IkiWiki::depends_simple{foo3}{foo3} == $IkiWiki::DEPEND_LINKS); ok(add_depends("foo4", $spec, links => 1)); ok($IkiWiki::depends{foo4}{$spec} & $IkiWiki::DEPEND_LINKS); ok(! ($IkiWiki::depends{foo4}{$spec} & ($IkiWiki::DEPEND_CONTENT | $IkiWiki::DEPEND_PRESENCE))); - ok($IkiWiki::depends_simple{foo4}{foo4} == $IkiWiki::DEPEND_CONTENT); + ok($IkiWiki::depends_simple{foo4}{foo4} == $IkiWiki::DEPEND_LINKS); } # a pagespec with backlinks() will add as an influence the page with the links @@ -76,20 +76,20 @@ foreach my $spec ("bugs or (backlink(foo0) and !*.png)", "backlink(foo)") { ok(add_depends("foo5", $spec, presence => 1)); ok($IkiWiki::depends{foo5}{$spec} & $IkiWiki::DEPEND_PRESENCE); ok(! ($IkiWiki::depends{foo5}{$spec} & ($IkiWiki::DEPEND_CONTENT | $IkiWiki::DEPEND_LINKS))); - ok($IkiWiki::depends_simple{foo5}{foo0} == $IkiWiki::DEPEND_CONTENT); + ok($IkiWiki::depends_simple{foo5}{foo0} == $IkiWiki::DEPEND_LINKS); ok(add_depends("foo6", $spec, links => 1)); ok($IkiWiki::depends{foo6}{$spec} & $IkiWiki::DEPEND_LINKS); ok(! ($IkiWiki::depends{foo6}{$spec} & ($IkiWiki::DEPEND_PRESENCE | $IkiWiki::DEPEND_CONTENT))); - ok($IkiWiki::depends_simple{foo5}{foo0} == $IkiWiki::DEPEND_CONTENT); + ok($IkiWiki::depends_simple{foo5}{foo0} == $IkiWiki::DEPEND_LINKS); ok(add_depends("foo7", $spec, presence => 1, links => 1)); ok($IkiWiki::depends{foo7}{$spec} & $IkiWiki::DEPEND_PRESENCE); ok($IkiWiki::depends{foo7}{$spec} & $IkiWiki::DEPEND_LINKS); ok(! ($IkiWiki::depends{foo7}{$spec} & $IkiWiki::DEPEND_CONTENT)); - ok($IkiWiki::depends_simple{foo7}{foo0} == $IkiWiki::DEPEND_CONTENT); + ok($IkiWiki::depends_simple{foo7}{foo0} == $IkiWiki::DEPEND_LINKS); ok(add_depends("foo8", $spec)); ok($IkiWiki::depends{foo8}{$spec} & $IkiWiki::DEPEND_CONTENT); ok(! ($IkiWiki::depends{foo8}{$spec} & ($IkiWiki::DEPEND_PRESENCE | $IkiWiki::DEPEND_LINKS))); - ok($IkiWiki::depends_simple{foo8}{foo0} == $IkiWiki::DEPEND_CONTENT); + ok($IkiWiki::depends_simple{foo8}{foo0} == $IkiWiki::DEPEND_LINKS); } # content is the default if unknown types are entered diff --git a/t/pagespec_match.t b/t/pagespec_match.t index 1a0db1cef..36fa04370 100755 --- a/t/pagespec_match.t +++ b/t/pagespec_match.t @@ -93,19 +93,19 @@ $ret=pagespec_match("foo", "bar or foo"); ok($ret, "simple match"); is($ret, "foo matches foo", "stringified return"); -$ret=pagespec_match("foo", "link(bar)"); -is(join(",", $ret->influences), 'foo', "link is influenced by the page with the link"); -$ret=pagespec_match("bar", "backlink(foo)"); -is(join(",", $ret->influences), 'foo', "backlink is influenced by the page with the link"); -$ret=pagespec_match("bar", "backlink(foo)"); -is(join(",", $ret->influences), 'foo', "backlink is influenced by the page with the link"); -$ret=pagespec_match("bar", "created_before(foo)"); -is(join(",", $ret->influences), 'foo', "created_before is influenced by the comparison page"); -$ret=pagespec_match("bar", "created_after(foo)"); -is(join(",", $ret->influences), 'foo', "created_after is influenced by the comparison page"); -$ret=pagespec_match("bar", "link(quux) and created_after(foo)"); -is(join(",", sort $ret->influences), 'foo,quux', "influences add up over AND"); -$ret=pagespec_match("bar", "link(quux) and created_after(foo)"); -is(join(",", sort $ret->influences), 'foo,quux', "influences add up over OR"); -$ret=pagespec_match("bar", "!link(quux) and !created_after(foo)"); -is(join(",", sort $ret->influences), 'foo,quux', "influences unaffected by negation"); +my %i=pagespec_match("foo", "link(bar)")->influences; +is(join(",", keys %i), 'foo', "link is influenced by the page with the link"); +%i=pagespec_match("bar", "backlink(foo)")->influences; +is(join(",", keys %i), 'foo', "backlink is influenced by the page with the link"); +%i=pagespec_match("bar", "backlink(foo)")->influences; +is(join(",", keys %i), 'foo', "backlink is influenced by the page with the link"); +%i=pagespec_match("bar", "created_before(foo)")->influences; +is(join(",", keys %i), 'foo', "created_before is influenced by the comparison page"); +%i=pagespec_match("bar", "created_after(foo)")->influences; +is(join(",", keys %i), 'foo', "created_after is influenced by the comparison page"); +%i=pagespec_match("bar", "link(quux) and created_after(foo)")->influences; +is(join(",", sort keys %i), 'bar,foo', "influences add up over AND"); +%i=pagespec_match("bar", "link(quux) and created_after(foo)")->influences; +is(join(",", sort keys %i), 'bar,foo', "influences add up over OR"); +%i=pagespec_match("bar", "!link(quux) and !created_after(foo)")->influences; +is(join(",", sort keys %i), 'bar,foo', "influences unaffected by negation"); -- cgit v1.2.3 From 957ded9d64ca6abf0127c5c49e24177685bac5ae Mon Sep 17 00:00:00 2001 From: Joey Hess Date: Wed, 7 Oct 2009 21:57:31 -0400 Subject: remove explicit addition of dependencies for displayed pages that hack is not needed, thanks to pagespec influences calculation --- IkiWiki/Plugin/calendar.pm | 5 ----- IkiWiki/Plugin/inline.pm | 6 ------ IkiWiki/Plugin/map.pm | 5 ----- 3 files changed, 16 deletions(-) diff --git a/IkiWiki/Plugin/calendar.pm b/IkiWiki/Plugin/calendar.pm index a1117992a..ec8e232e1 100644 --- a/IkiWiki/Plugin/calendar.pm +++ b/IkiWiki/Plugin/calendar.pm @@ -213,11 +213,6 @@ EOF # Add dependencies to update the calendar whenever pages # matching the pagespec are added or removed. add_depends($params{page}, $params{pages}, presence => 1); - # Explicitly add all currently linked pages as dependencies, so - # that if they are removed, the calendar will be sure to be updated. - foreach my $p (@list) { - add_depends($params{page}, $p, presence => 1); - } return $calendar; } diff --git a/IkiWiki/Plugin/inline.pm b/IkiWiki/Plugin/inline.pm index cebd9037c..fc4e00a83 100644 --- a/IkiWiki/Plugin/inline.pm +++ b/IkiWiki/Plugin/inline.pm @@ -247,12 +247,6 @@ sub preprocess_inline (@) { @list=@list[0..$params{show} - 1]; } - # Explicitly add all currently displayed pages as dependencies, so - # that if they are removed, the inline will be sure to be updated. - foreach my $p ($#list >= $#feedlist ? @list : @feedlist) { - add_depends($params{page}, $p, presence => $quick); - } - if ($feeds && exists $params{feedpages}) { @feedlist=pagespec_match_list(\@feedlist, $params{feedpages}, location => $params{page}); } diff --git a/IkiWiki/Plugin/map.pm b/IkiWiki/Plugin/map.pm index 625cfdfca..46f11dc89 100644 --- a/IkiWiki/Plugin/map.pm +++ b/IkiWiki/Plugin/map.pm @@ -71,11 +71,6 @@ sub preprocess (@) { # cases, when its content changes, if show= is specified), so # register a dependency. add_depends($params{page}, $params{pages}, presence => ! exists $params{show}); - # Explicitly add all currently shown pages, to detect when pages - # are removed. - foreach my $item (keys %mapitems) { - add_depends($params{page}, $item, presence => ! exists $params{show}); - } # Create the map. my $parent=""; -- cgit v1.2.3 From 0cb08c9a4b558c3a0a13c5652b0e0a37ae548199 Mon Sep 17 00:00:00 2001 From: Joey Hess Date: Wed, 7 Oct 2009 22:08:19 -0400 Subject: bugfix --- IkiWiki.pm | 1 + 1 file changed, 1 insertion(+) diff --git a/IkiWiki.pm b/IkiWiki.pm index 39a43ddbe..c250d50ad 100644 --- a/IkiWiki.pm +++ b/IkiWiki.pm @@ -1795,6 +1795,7 @@ sub add_depends ($$;@) { return if $@; foreach my $p (keys %pagesources) { my $r=$sub->($p, location => $page ); + next unless $r; my %i=$r->influences; foreach my $i (keys %i) { $depends_simple{$page}{lc $i} |= $i{$i}; -- cgit v1.2.3 From f2b3d1341447cbf29189ab490daae418fbe5d02d Mon Sep 17 00:00:00 2001 From: Joey Hess Date: Thu, 8 Oct 2009 13:38:46 -0400 Subject: fix handling of influences of pagespecs that fail to match If a pagespec fails to match, I had been throwing the influences away, but that is not right. Consider `backlink(foo)`, where foo does not exist. It still needs to be added as an influence, because if it is created, it will influence the pagespec to match. But with that fix, `link(bar)` had as influences all pages, whether they link to bar or not. Which is not necessary, because modifiying a page to add a link to bar will directly cause the pagespec to match. So, in match_link (and all the match_* functions for page metadata), only return an influence if the match succeeds. match_backlink had been implemented as the inverse of match_link, but that is no longer completly true. While match_link does not return an influence on failure, match_backlink does. match_created_before/after also return the influence on failure, this way if created_after(foo) currently fails because foo does not exist, it will still update the page with the pagespec if foo is created. --- IkiWiki.pm | 21 ++++++++++++++------- IkiWiki/Plugin/meta.pm | 4 ++-- 2 files changed, 16 insertions(+), 9 deletions(-) diff --git a/IkiWiki.pm b/IkiWiki.pm index c250d50ad..2064c881a 100644 --- a/IkiWiki.pm +++ b/IkiWiki.pm @@ -1789,13 +1789,12 @@ sub add_depends ($$;@) { } # Analyse the pagespec, and match it against all pages - # to get a list of influences, and add explicit - # content dependencies for those. + # 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 ); - next unless $r; my %i=$r->influences; foreach my $i (keys %i) { $depends_simple{$page}{lc $i} |= $i{$i}; @@ -2026,7 +2025,13 @@ sub new { } sub influences { - return %{$_[0][1]}; + my $this=shift; + if (! @_) { + return %{$this->[1]}; + } + else { + $this->[1]={@_}; + } } sub merge_influences { @@ -2090,7 +2095,7 @@ sub match_link ($$;@) { my $from=exists $params{location} ? $params{location} : ''; my $links = $IkiWiki::links{$page}; - return IkiWiki::FailReason->new("$page has no links", $page => $IkiWiki::DEPEND_LINKS) + return IkiWiki::FailReason->new("$page has no links") unless $links && @{$links}; my $bestlink = IkiWiki::bestlink($from, $link); foreach my $p (@{$links}) { @@ -2107,11 +2112,13 @@ sub match_link ($$;@) { if match_glob($p_rel, $link, %params); } } - return IkiWiki::FailReason->new("$page does not link to $link", $page => $IkiWiki::DEPEND_LINKS); + return IkiWiki::FailReason->new("$page does not link to $link"); } sub match_backlink ($$;@) { - return match_link($_[1], $_[0], @_); + my $ret=match_link($_[1], $_[0], @_); + $ret->influences($_[1] => $IkiWiki::DEPEND_LINKS); + return $ret; } sub match_created_before ($$;@) { diff --git a/IkiWiki/Plugin/meta.pm b/IkiWiki/Plugin/meta.pm index c160e7eba..da3e62233 100644 --- a/IkiWiki/Plugin/meta.pm +++ b/IkiWiki/Plugin/meta.pm @@ -294,11 +294,11 @@ sub match { return IkiWiki::SuccessReason->new("$re matches $field of $page", $page => $IkiWiki::DEPEND_CONTENT); } else { - return IkiWiki::FailReason->new("$re does not match $field of $page", $page => $IkiWiki::DEPEND_CONTENT); + return IkiWiki::FailReason->new("$re does not match $field of $page"); } } else { - return IkiWiki::FailReason->new("$page does not have a $field", $page => $IkiWiki::DEPEND_CONTENT); + return IkiWiki::FailReason->new("$page does not have a $field"); } } -- cgit v1.2.3 From c57908b9d073500608d656adaf2bd3048c8cef67 Mon Sep 17 00:00:00 2001 From: Joey Hess Date: Thu, 8 Oct 2009 16:49:03 -0400 Subject: change how dependency types are specified to add_depends Also, this fixes 2 bugs in dependency info. --- IkiWiki/Plugin/brokenlinks.pm | 2 +- IkiWiki/Plugin/calendar.pm | 17 +++++++++-------- IkiWiki/Plugin/edittemplate.pm | 2 +- IkiWiki/Plugin/inline.pm | 7 ++++++- IkiWiki/Plugin/linkmap.pm | 2 +- IkiWiki/Plugin/listdirectives.pm | 2 +- IkiWiki/Plugin/map.pm | 3 ++- IkiWiki/Plugin/meta.pm | 2 +- IkiWiki/Plugin/orphans.pm | 4 ++-- IkiWiki/Plugin/pagecount.pm | 2 +- IkiWiki/Plugin/pagestats.pm | 4 ++-- IkiWiki/Plugin/postsparkline.pm | 2 +- IkiWiki/Plugin/progress.pm | 4 ++-- 13 files changed, 30 insertions(+), 23 deletions(-) diff --git a/IkiWiki/Plugin/brokenlinks.pm b/IkiWiki/Plugin/brokenlinks.pm index 9e65f52c6..62a0a42f4 100644 --- a/IkiWiki/Plugin/brokenlinks.pm +++ b/IkiWiki/Plugin/brokenlinks.pm @@ -24,7 +24,7 @@ sub preprocess (@) { $params{pages}="*" unless defined $params{pages}; # Needs to update whenever the links on a page change. - add_depends($params{page}, $params{pages}, links => 1); + add_depends($params{page}, $params{pages}, deptype("links")); my @broken; foreach my $link (keys %IkiWiki::brokenlinks) { diff --git a/IkiWiki/Plugin/calendar.pm b/IkiWiki/Plugin/calendar.pm index ec8e232e1..c99170f92 100644 --- a/IkiWiki/Plugin/calendar.pm +++ b/IkiWiki/Plugin/calendar.pm @@ -105,21 +105,21 @@ sub format_month (@) { linktext => " $monthname "); } add_depends($params{page}, "$archivebase/$year/".sprintf("%02d", $month), - presence => 1); + deptype("presence")); if (exists $cache{$pagespec}{"$pyear/$pmonth"}) { $purl = htmllink($params{page}, $params{destpage}, "$archivebase/$pyear/" . sprintf("%02d", $pmonth), linktext => " $pmonthname "); } add_depends($params{page}, "$archivebase/$pyear/".sprintf("%02d", $pmonth), - presence => 1); + deptype("presence")); if (exists $cache{$pagespec}{"$nyear/$nmonth"}) { $nurl = htmllink($params{page}, $params{destpage}, "$archivebase/$nyear/" . sprintf("%02d", $nmonth), linktext => " $nmonthname "); } add_depends($params{page}, "$archivebase/$nyear/".sprintf("%02d", $nmonth), - presence => 1); + deptype("presence")); # Start producing the month calendar $calendar=< 1); + add_depends($params{page}, $params{pages}, deptype("presence")); return $calendar; } @@ -244,19 +244,19 @@ sub format_year (@) { "$archivebase/$year", linktext => "$year"); } - add_depends($params{page}, "$archivebase/$year", presence => 1); + add_depends($params{page}, "$archivebase/$year", deptype("presence"); if (exists $cache{$pagespec}{"$pyear"}) { $purl = htmllink($params{page}, $params{destpage}, "$archivebase/$pyear", linktext => "\←"); } - add_depends($params{page}, "$archivebase/$pyear", presence => 1); + add_depends($params{page}, "$archivebase/$pyear", deptype("presence")); if (exists $cache{$pagespec}{"$nyear"}) { $nurl = htmllink($params{page}, $params{destpage}, "$archivebase/$nyear", linktext => "\→"); } - add_depends($params{page}, "$archivebase/$nyear", presence => 1); + add_depends($params{page}, "$archivebase/$nyear", deptype("presence")); # Start producing the year calendar $calendar=<$monthabbr\n}; } - add_depends($params{page}, "$archivebase/$year/$mtag", presence => 1); + add_depends($params{page}, "$archivebase/$year/$mtag", + deptype("presence")); $calendar.=qq{\t\n} if ($month % $params{months_per_row} == 0); } diff --git a/IkiWiki/Plugin/edittemplate.pm b/IkiWiki/Plugin/edittemplate.pm index 2dd1dbe68..7d2eba194 100644 --- a/IkiWiki/Plugin/edittemplate.pm +++ b/IkiWiki/Plugin/edittemplate.pm @@ -58,7 +58,7 @@ sub preprocess (@) { $pagestate{$params{page}}{edittemplate}{$params{match}}=$link; return "" if ($params{silent} && IkiWiki::yesno($params{silent})); - add_depends($params{page}, $link, presence => 1); + add_depends($params{page}, $link, deptype("presence")); return sprintf(gettext("edittemplate %s registered for %s"), htmllink($params{page}, $params{destpage}, $link), $params{match}); diff --git a/IkiWiki/Plugin/inline.pm b/IkiWiki/Plugin/inline.pm index fc4e00a83..be1781520 100644 --- a/IkiWiki/Plugin/inline.pm +++ b/IkiWiki/Plugin/inline.pm @@ -195,9 +195,14 @@ sub preprocess_inline (@) { @list = map { bestlink($params{page}, $_) } split ' ', $params{pagenames}; + + foreach my $p (@list) { + add_depends($params{page}, $p, deptype($quick ? "presence" : "content")); + } } else { - add_depends($params{page}, $params{pages}, presence => $quick); + add_depends($params{page}, $params{pages}, + deptype($quick ? "presence" : "content")); @list = pagespec_match_list( [ grep { $_ ne $params{page} } keys %pagesources ], diff --git a/IkiWiki/Plugin/linkmap.pm b/IkiWiki/Plugin/linkmap.pm index 3d20a6521..28e4cfa13 100644 --- a/IkiWiki/Plugin/linkmap.pm +++ b/IkiWiki/Plugin/linkmap.pm @@ -30,7 +30,7 @@ sub preprocess (@) { # Needs to update whenever a relevant page is added, or removed, or # its links change. - add_depends($params{page}, $params{pages}, presence => 1, links => 1); + add_depends($params{page}, $params{pages}, deptype("presence", "links")); # Can't just return the linkmap here, since the htmlscrubber # scrubs out all tags (with good reason!) diff --git a/IkiWiki/Plugin/listdirectives.pm b/IkiWiki/Plugin/listdirectives.pm index 4023ed7d7..09f08c567 100644 --- a/IkiWiki/Plugin/listdirectives.pm +++ b/IkiWiki/Plugin/listdirectives.pm @@ -84,7 +84,7 @@ sub preprocess (@) { foreach my $plugin (@pluginlist) { $result .= '
  • '; my $link=linkpage($config{directive_description_dir}."/".$plugin); - add_depends($params{page}, $link, presence => 1); + add_depends($params{page}, $link, deptype("presence")); $result .= htmllink($params{page}, $params{destpage}, $link); $result .= '
  • '; } diff --git a/IkiWiki/Plugin/map.pm b/IkiWiki/Plugin/map.pm index 46f11dc89..19872e51c 100644 --- a/IkiWiki/Plugin/map.pm +++ b/IkiWiki/Plugin/map.pm @@ -70,7 +70,8 @@ sub preprocess (@) { # Needs to update whenever a page is added or removed (or in some # cases, when its content changes, if show= is specified), so # register a dependency. - add_depends($params{page}, $params{pages}, presence => ! exists $params{show}); + add_depends($params{page}, $params{pages}, + deptype(exists $params{show} ? "content" : "presence"); # Create the map. my $parent=""; diff --git a/IkiWiki/Plugin/meta.pm b/IkiWiki/Plugin/meta.pm index da3e62233..c675880b3 100644 --- a/IkiWiki/Plugin/meta.pm +++ b/IkiWiki/Plugin/meta.pm @@ -195,7 +195,7 @@ sub preprocess (@) { if (! length $link) { error gettext("redir page not found") } - add_depends($page, $link, presence => 1); + add_depends($page, $link, deptype("presence")); $value=urlto($link, $page); $value.='#'.$redir_anchor if defined $redir_anchor; diff --git a/IkiWiki/Plugin/orphans.pm b/IkiWiki/Plugin/orphans.pm index ae330b23b..93b8ec440 100644 --- a/IkiWiki/Plugin/orphans.pm +++ b/IkiWiki/Plugin/orphans.pm @@ -26,10 +26,10 @@ sub preprocess (@) { # Needs to update whenever a link changes, on any page # since any page could link to one of the pages we're # considering as orphans. - add_depends($params{page}, "*", links => 1); + add_depends($params{page}, "*", deptype("links")); # Also needs to update whenever potential orphans are added or # removed. - add_depends($params{page}, $params{pages}, presence => 1); + add_depends($params{page}, $params{pages}, deptype("presence")); my @orphans; foreach my $page (pagespec_match_list( diff --git a/IkiWiki/Plugin/pagecount.pm b/IkiWiki/Plugin/pagecount.pm index 80561350b..419f2d535 100644 --- a/IkiWiki/Plugin/pagecount.pm +++ b/IkiWiki/Plugin/pagecount.pm @@ -24,7 +24,7 @@ sub preprocess (@) { # Needs to update count whenever a page is added or removed, so # register a presence dependency. - add_depends($params{page}, $params{pages}, presence => 1); + add_depends($params{page}, $params{pages}, deptype("presence")); my @pages; if ($params{pages} eq "*") { diff --git a/IkiWiki/Plugin/pagestats.pm b/IkiWiki/Plugin/pagestats.pm index afe4eeaf2..cd0bdb085 100644 --- a/IkiWiki/Plugin/pagestats.pm +++ b/IkiWiki/Plugin/pagestats.pm @@ -36,12 +36,12 @@ sub preprocess (@) { my $style = ($params{style} or 'cloud'); # Needs to update whenever a page is added or removed. - add_depends($params{page}, $params{pages}, exists => 1); + add_depends($params{page}, $params{pages}, deptype("presence")); # Also needs to update when any page with links changes, # in case the links point to our displayed pages. # (Among limits this further.) add_depends($params{page}, exists $params{among} ? $params{among} : "*", - links => 1); + deptype("links")); my %counts; my $max = 0; diff --git a/IkiWiki/Plugin/postsparkline.pm b/IkiWiki/Plugin/postsparkline.pm index 3205958d4..ea73e9180 100644 --- a/IkiWiki/Plugin/postsparkline.pm +++ b/IkiWiki/Plugin/postsparkline.pm @@ -48,7 +48,7 @@ sub preprocess (@) { error gettext("unknown formula"); } - add_depends($params{page}, $params{pages}, presence => 1); + add_depends($params{page}, $params{pages}, deptype("presence")); my @list=sort { $params{timehash}->{$b} <=> $params{timehash}->{$a} } pagespec_match_list( diff --git a/IkiWiki/Plugin/progress.pm b/IkiWiki/Plugin/progress.pm index 26c537a84..6da3e4f71 100644 --- a/IkiWiki/Plugin/progress.pm +++ b/IkiWiki/Plugin/progress.pm @@ -36,8 +36,8 @@ sub preprocess (@) { $fill.="%"; } elsif (defined $params{totalpages} and defined $params{donepages}) { - add_depends($params{page}, $params{totalpages}, presence => 1); - add_depends($params{page}, $params{donepages}, presence => 1); + add_depends($params{page}, $params{totalpages}, deptype("presence")); + add_depends($params{page}, $params{donepages}, deptype("presence")); my @pages=keys %pagesources; my $totalcount=0; -- cgit v1.2.3 From 5e236f5d25b68f5fb4a421b24470419c6042cb1c Mon Sep 17 00:00:00 2001 From: Joey Hess Date: Thu, 8 Oct 2009 16:49:53 -0400 Subject: add use_pagespec and deptype functions --- IkiWiki.pm | 135 +++++++++++++++++++++++++++++++++++++++++-------- debian/changelog | 4 +- doc/plugins/write.mdwn | 61 +++++++++++++++++----- t/use_pagespec.t | 30 +++++++++++ 4 files changed, 194 insertions(+), 36 deletions(-) create mode 100755 t/use_pagespec.t diff --git a/IkiWiki.pm b/IkiWiki.pm index 2064c881a..c787612e1 100644 --- a/IkiWiki.pm +++ b/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,18 +1784,118 @@ 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}; + # } + #} + 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); - return if $@; - foreach my $p (keys %pagesources) { - my $r=$sub->($p, location => $page ); - my %i=$r->influences; + 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)); } - $depends{$page}{$pagespec} |= $deptype; - return 1; + 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 ($$) { diff --git a/debian/changelog b/debian/changelog index 565a0cffa..12ddebac9 100644 --- a/debian/changelog +++ b/debian/changelog @@ -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 Sun, 27 Sep 2009 17:40:03 -0400 diff --git a/doc/plugins/write.mdwn b/doc/plugins/write.mdwn index 232430079..3d5650758 100644 --- a/doc/plugins/write.mdwn +++ b/doc/plugins/write.mdwn @@ -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 diff --git a/t/use_pagespec.t b/t/use_pagespec.t new file mode 100755 index 000000000..7b904075e --- /dev/null +++ b/t/use_pagespec.t @@ -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"); -- cgit v1.2.3 From de24c0df873a772a8b44098d1b4d2e1258640c9e Mon Sep 17 00:00:00 2001 From: Joey Hess Date: Thu, 8 Oct 2009 17:52:20 -0400 Subject: map: switch to use_pagespec --- IkiWiki/Plugin/map.pm | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/IkiWiki/Plugin/map.pm b/IkiWiki/Plugin/map.pm index 19872e51c..634b0e4d6 100644 --- a/IkiWiki/Plugin/map.pm +++ b/IkiWiki/Plugin/map.pm @@ -28,12 +28,15 @@ sub preprocess (@) { my %params=@_; $params{pages}="*" unless defined $params{pages}; + # Needs to update whenever a page is added or removed (or in some + # cases, when its content changes, if show= is specified). + my $deptype=deptype(exists $params{show} ? "content" : "presence"); + my $common_prefix; # Get all the items to map. my %mapitems; - foreach my $page (pagespec_match_list([keys %pagesources], - $params{pages}, location => $params{page})) { + foreach my $page (use_pagespec($params{page}, $params{pages}, deptype => $deptype)) { if (exists $params{show} && exists $pagestate{$page} && exists $pagestate{$page}{meta}{$params{show}}) { @@ -67,12 +70,6 @@ sub preprocess (@) { $common_prefix=IkiWiki::dirname($common_prefix); } - # Needs to update whenever a page is added or removed (or in some - # cases, when its content changes, if show= is specified), so - # register a dependency. - add_depends($params{page}, $params{pages}, - deptype(exists $params{show} ? "content" : "presence"); - # Create the map. my $parent=""; my $indent=0; @@ -80,12 +77,12 @@ sub preprocess (@) { my $addparent=""; my $map = "
    \n"; - # Return empty div if %mapitems is empty - if (!scalar(keys %mapitems)) { + if (! keys %mapitems) { + # return empty div for empty map $map .= "
    \n"; return $map; } - else { # continue populating $map + else { $map .= "
      \n"; } -- cgit v1.2.3 From 65d57902ca9f05b7958ea0a47b3fa3c651da89f5 Mon Sep 17 00:00:00 2001 From: Joey Hess Date: Thu, 8 Oct 2009 18:17:36 -0400 Subject: add sorting page --- doc/ikiwiki/directive/inline.mdwn | 8 ++------ doc/ikiwiki/pagespec/sorting.mdwn | 11 +++++++++++ 2 files changed, 13 insertions(+), 6 deletions(-) create mode 100644 doc/ikiwiki/pagespec/sorting.mdwn diff --git a/doc/ikiwiki/directive/inline.mdwn b/doc/ikiwiki/directive/inline.mdwn index 4e087ab6c..c6a23ce3c 100644 --- a/doc/ikiwiki/directive/inline.mdwn +++ b/doc/ikiwiki/directive/inline.mdwn @@ -86,12 +86,8 @@ Here are some less often needed parameters: if raw is set to "yes", the page will be included raw, without additional markup around it, as if it were a literal part of the source of the inlining page. -* `sort` - Controls how inlined pages are sorted. The default, "age" is to - sort newest created pages first. Setting it to "title" will sort pages by - title, and "mtime" sorts most recently modified pages first. If - [[!cpan Sort::Naturally]] is installed, `sort` can be set to "title_natural" - to sort by title with numbers treated as such ("1 2 9 10 20" instead of - "1 10 2 20 9"). +* `sort` - Controls how inlined pages are [[sorted|pagespec/sorting]]. + The default is to sort the newest created pages first. * `reverse` - If set to "yes", causes the sort order to be reversed. * `feedshow` - Specify the maximum number of matching pages to include in the rss/atom feeds. The default is the same as the `show` value above. diff --git a/doc/ikiwiki/pagespec/sorting.mdwn b/doc/ikiwiki/pagespec/sorting.mdwn new file mode 100644 index 000000000..1e0366029 --- /dev/null +++ b/doc/ikiwiki/pagespec/sorting.mdwn @@ -0,0 +1,11 @@ +Some [[directives|ikiwiki/directive]] that use +[[PageSpecs|ikiwiki/pagespec]], such as [[ikiwiki/directive/inline]], allow +specifying the order that matching pages are shown in. The following sort +orders can be specified. + +* `age` - List pages from the most recently created to the oldest. +* `mtime` - List pages with the most recently modified first. +* `title` - Order by title. +* `title_natural` - Only available if [[!cpan Sort::Naturally]] is + installed. Orders by title, but numbers in the title are treated + as such, ("1 2 9 10 20" instead of "1 10 2 20 9") -- cgit v1.2.3 From 32cd5f0b798c41b2320a4165c5b6ecc18a4e6e3e Mon Sep 17 00:00:00 2001 From: Joey Hess Date: Thu, 8 Oct 2009 18:26:36 -0400 Subject: inline: switch to use_pagespec Taking advantage of every single one of its features, of course. Even had to add one more.. --- IkiWiki/Plugin/inline.pm | 49 +++++++++++++++++++++--------------------------- doc/plugins/write.mdwn | 2 ++ 2 files changed, 23 insertions(+), 28 deletions(-) diff --git a/IkiWiki/Plugin/inline.pm b/IkiWiki/Plugin/inline.pm index be1781520..748e02df4 100644 --- a/IkiWiki/Plugin/inline.pm +++ b/IkiWiki/Plugin/inline.pm @@ -196,45 +196,37 @@ sub preprocess_inline (@) { @list = map { bestlink($params{page}, $_) } split ' ', $params{pagenames}; + if (yesno($params{reverse})) { + @list=reverse(@list); + } + foreach my $p (@list) { add_depends($params{page}, $p, deptype($quick ? "presence" : "content")); } } else { - add_depends($params{page}, $params{pages}, - deptype($quick ? "presence" : "content")); - - @list = pagespec_match_list( - [ grep { $_ ne $params{page} } keys %pagesources ], - $params{pages}, location => $params{page}); - - if (exists $params{sort} && $params{sort} eq 'title') { - @list=sort { pagetitle(basename($a)) cmp pagetitle(basename($b)) } @list; + my $num=0; + if ($params{show}) { + $num=$params{show}; } - elsif (exists $params{sort} && $params{sort} eq 'title_natural') { - eval q{use Sort::Naturally}; - if ($@) { - error(gettext("Sort::Naturally needed for title_natural sort")); - } - @list=sort { Sort::Naturally::ncmp(pagetitle(basename($a)), pagetitle(basename($b))) } @list; + if ($params{feedshow} && $num < $params{feedshow}) { + $num=$params{feedshow}; } - elsif (exists $params{sort} && $params{sort} eq 'mtime') { - @list=sort { $pagemtime{$b} <=> $pagemtime{$a} } @list; + if ($params{skip}) { + $num+=$params{skip}; } - elsif (! exists $params{sort} || $params{sort} eq 'age') { - @list=sort { $pagectime{$b} <=> $pagectime{$a} } @list; - } - else { - error sprintf(gettext("unknown sort type %s"), $params{sort}); - } - } - if (yesno($params{reverse})) { - @list=reverse(@list); + @list = use_pagespec($params{page}, $params{pages}, + deptype => deptype($quick ? "presence" : "content"), + limit => sub { $_[0] ne $params{page} }, + sort => exists $params{sort} ? $params{sort} : "age", + reverse => yesno($params{reverse}), + num => $num, + ); } if (exists $params{skip}) { - @list=@list[$params{skip} .. scalar @list - 1]; + @list=@list[$params{skip} .. $#list]; } my @feedlist; @@ -253,7 +245,8 @@ sub preprocess_inline (@) { } if ($feeds && exists $params{feedpages}) { - @feedlist=pagespec_match_list(\@feedlist, $params{feedpages}, location => $params{page}); + @feedlist = use_pagespec($params{page}, $params{feedpages}, + list => \@feedlist); } my ($feedbase, $feednum); diff --git a/doc/plugins/write.mdwn b/doc/plugins/write.mdwn index 3d5650758..62bebbeed 100644 --- a/doc/plugins/write.mdwn +++ b/doc/plugins/write.mdwn @@ -647,6 +647,8 @@ Additional named parameters can be specified: * `reverse` if true, sorts in reverse. * `num` if nonzero, specifies the maximum number of matching pages that will be returned. +* `list` makes it only match amoung the specified list of pages. + Default is to match amoung all pages in the wiki. #### `add_depends($$;$)` -- cgit v1.2.3 From 1abbc6a4041e752fbec9b947a9d453b3b126c120 Mon Sep 17 00:00:00 2001 From: Joey Hess Date: Thu, 8 Oct 2009 18:41:08 -0400 Subject: pagecount: switched to use_pagespec --- IkiWiki/Plugin/pagecount.pm | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/IkiWiki/Plugin/pagecount.pm b/IkiWiki/Plugin/pagecount.pm index 419f2d535..40474b2a1 100644 --- a/IkiWiki/Plugin/pagecount.pm +++ b/IkiWiki/Plugin/pagecount.pm @@ -20,20 +20,20 @@ sub getsetup () { sub preprocess (@) { my %params=@_; - $params{pages}="*" unless defined $params{pages}; + my $pages=defined $params{pages} ? $params{pages} : "*"; - # Needs to update count whenever a page is added or removed, so - # register a presence dependency. - add_depends($params{page}, $params{pages}, deptype("presence")); - - my @pages; - if ($params{pages} eq "*") { - @pages=keys %pagesources; - } - else { - @pages=pagespec_match_list([keys %pagesources], $params{pages}, location => $params{page}); + # Just get a list of all the pages, and count the items in it. + # Use a presence dependency to only update when pages are added + # or removed. + + if ($pages eq '*') { + # optimisation to avoid needing to try matching every page + add_depends($params{page}, $pages, deptype("presence")); + return scalar keys %pagesources; } - return $#pages+1; + + return scalar use_pagespec($params{page}, $pages, + deptype => deptype("presence")); } 1 -- cgit v1.2.3 From d5f014449511460d4da22591379b30bd5de86145 Mon Sep 17 00:00:00 2001 From: Joey Hess Date: Thu, 8 Oct 2009 18:47:48 -0400 Subject: use_pagespec: do not fail with error when unable to match, unless it fails with an ErrorReason --- IkiWiki.pm | 4 +++- t/use_pagespec.t | 7 ++++--- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/IkiWiki.pm b/IkiWiki.pm index c787612e1..c735b26c8 100644 --- a/IkiWiki.pm +++ b/IkiWiki.pm @@ -1876,7 +1876,9 @@ sub use_pagespec ($$;@) { foreach my $i (keys %i) { $depends_simple{$page}{lc $i} |= $i{$i}; } - error(sprintf(gettext("cannot match pages: %s"), $firstfail)); + + error(sprintf(gettext("cannot match pages: %s"), $firstfail)) + if $firstfail->isa("IkiWiki::ErrorReason"); } return @ret; diff --git a/t/use_pagespec.t b/t/use_pagespec.t index 7b904075e..92d7977cf 100755 --- a/t/use_pagespec.t +++ b/t/use_pagespec.t @@ -1,7 +1,7 @@ #!/usr/bin/perl use warnings; use strict; -use Test::More tests => 64; +use Test::More tests => 10; BEGIN { use_ok("IkiWiki"); } @@ -24,7 +24,8 @@ is_deeply([use_pagespec("foo", "post/*", sort => "title", num => 50)], 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"); +my $r=eval { use_pagespec("foo", "beep") }; +ok(eval { use_pagespec("foo", "beep") } == 0); +ok(! $@, "does not fail with error when unable to match anything"); eval { use_pagespec("foo", "this is not a legal pagespec!") }; ok($@, "fails with error when pagespec bad"); -- cgit v1.2.3 From bc4ef28f3ebc396096b7eccad04eea6febac8d38 Mon Sep 17 00:00:00 2001 From: Joey Hess Date: Thu, 8 Oct 2009 19:27:25 -0400 Subject: pagestate: switch to use_pagespec --- IkiWiki/Plugin/pagestats.pm | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/IkiWiki/Plugin/pagestats.pm b/IkiWiki/Plugin/pagestats.pm index cd0bdb085..e64f7d9c3 100644 --- a/IkiWiki/Plugin/pagestats.pm +++ b/IkiWiki/Plugin/pagestats.pm @@ -35,25 +35,27 @@ sub preprocess (@) { $params{pages}="*" unless defined $params{pages}; my $style = ($params{style} or 'cloud'); - # Needs to update whenever a page is added or removed. - add_depends($params{page}, $params{pages}, deptype("presence")); - # Also needs to update when any page with links changes, - # in case the links point to our displayed pages. - # (Among limits this further.) - add_depends($params{page}, exists $params{among} ? $params{among} : "*", - deptype("links")); - my %counts; my $max = 0; - foreach my $page (pagespec_match_list([keys %pagesources], - $params{pages}, location => $params{page})) { + foreach my $page (use_pagespec($params{page}, $params{pages}, + # update when a displayed page is added or removed + deptype => deptype("presence"))) { use IkiWiki::Render; my @backlinks = IkiWiki::backlink_pages($page); if (exists $params{among}) { - @backlinks = pagespec_match_list(\@backlinks, - $params{among}, location => $params{page}); + # only consider backlinks from the amoung pages + @backlinks = use_pagespec($params{page}, $params{among}, + # update whenever links on those pages change + deptype => deptype("links"), + list => \@backlinks + ); + } + else { + # update when any page with links changes, + # in case the links point to our displayed pages + add_depends($params{page}, "*", deptype("links")); } $counts{$page} = scalar(@backlinks); -- cgit v1.2.3 From 57d04ed892588cbb49bfa81e2453e88388e67441 Mon Sep 17 00:00:00 2001 From: Joey Hess Date: Thu, 8 Oct 2009 20:54:06 -0400 Subject: fix feedpages dependency This dependency was missing before switching to use_pagespec. It is correct to add it, but it needs to be combined with the regular "pages" dependency to ensure that it does not match extra pages. (Also fixed its dependency type.) --- IkiWiki/Plugin/inline.pm | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/IkiWiki/Plugin/inline.pm b/IkiWiki/Plugin/inline.pm index 748e02df4..c02137aed 100644 --- a/IkiWiki/Plugin/inline.pm +++ b/IkiWiki/Plugin/inline.pm @@ -245,7 +245,8 @@ sub preprocess_inline (@) { } if ($feeds && exists $params{feedpages}) { - @feedlist = use_pagespec($params{page}, $params{feedpages}, + @feedlist = use_pagespec($params{page}, "($params{pages}) and ($params{feedpages})", + deptype => deptype($quick ? "presence" : "content"), list => \@feedlist); } -- cgit v1.2.3 From 3be7a02e7d0a4f19ffba3566d9aedee2885387d4 Mon Sep 17 00:00:00 2001 From: Joey Hess Date: Thu, 8 Oct 2009 22:56:12 -0400 Subject: orphans: switch to use_pagespec --- IkiWiki/Plugin/orphans.pm | 40 +++++++++++++++++++++++----------------- 1 file changed, 23 insertions(+), 17 deletions(-) diff --git a/IkiWiki/Plugin/orphans.pm b/IkiWiki/Plugin/orphans.pm index 93b8ec440..607239500 100644 --- a/IkiWiki/Plugin/orphans.pm +++ b/IkiWiki/Plugin/orphans.pm @@ -27,24 +27,30 @@ sub preprocess (@) { # since any page could link to one of the pages we're # considering as orphans. add_depends($params{page}, "*", deptype("links")); - # Also needs to update whenever potential orphans are added or - # removed. - add_depends($params{page}, $params{pages}, deptype("presence")); - my @orphans; - foreach my $page (pagespec_match_list( - [ grep { ! IkiWiki::backlink_pages($_) && $_ ne 'index' } - keys %pagesources ], - $params{pages}, location => $params{page})) { - # If the page has a link to some other page, it's - # indirectly linked to a page via that page's backlinks. - next if grep { - length $_ && - ($_ !~ /\/\Q$config{discussionpage}\E$/i || ! $config{discussion}) && - bestlink($page, $_) !~ /^(\Q$page\E|)$/ - } @{$links{$page}}; - push @orphans, $page; - } + my @orphans=use_pagespec($params{page}, $params{pages}, + # update when orphans are added/removed + deptype => deptype("presence"), + limit => sub { + my $page=shift; + + # Filter out pages that other pages link to. + return 0 if IkiWiki::backlink_pages($page); + + # Toplevel index is assumed to never be orphaned. + return 0 if $page eq 'index'; + + # If the page has a link to some other page, it's + # indirectly linked via that page's backlinks. + return 0 if grep { + length $_ && + ($_ !~ /\/\Q$config{discussionpage}\E$/i || ! $config{discussion}) && + bestlink($page, $_) !~ /^(\Q$page\E|)$/ + } @{$links{$page}}; + + return 1; + }, + ); return gettext("All pages have other pages linking to them.") unless @orphans; return "
        \n". -- cgit v1.2.3 From 80ab1dbc121fa74fe2f021a5af2b941c743c332d Mon Sep 17 00:00:00 2001 From: Joey Hess Date: Thu, 8 Oct 2009 22:56:36 -0400 Subject: postsparkline: switch to use_pagespec Also, fixed up the dependency type for time=mtime. That has to remain a content dependency, sadly. --- IkiWiki/Plugin/postsparkline.pm | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/IkiWiki/Plugin/postsparkline.pm b/IkiWiki/Plugin/postsparkline.pm index ea73e9180..f51e309c8 100644 --- a/IkiWiki/Plugin/postsparkline.pm +++ b/IkiWiki/Plugin/postsparkline.pm @@ -30,11 +30,16 @@ sub preprocess (@) { return ""; } + my $deptype; if (! exists $params{time} || $params{time} ne 'mtime') { $params{timehash} = \%IkiWiki::pagectime; + # need to update when pages are added or removed + $deptype = deptype("presence"); } else { $params{timehash} = \%IkiWiki::pagemtime; + # need to update when pages are changed + $deptype = deptype("content"); } if (! exists $params{formula}) { @@ -48,12 +53,11 @@ sub preprocess (@) { error gettext("unknown formula"); } - add_depends($params{page}, $params{pages}, deptype("presence")); - my @list=sort { $params{timehash}->{$b} <=> $params{timehash}->{$a} } - pagespec_match_list( - [ grep { $_ ne $params{page} } keys %pagesources], - $params{pages}, location => $params{page}); + use_pagespec($params{page}, $params{pages}, + deptype => $deptype, + limit => sub { $_[0] ne $params{page} }, + ); my @data=eval qq{IkiWiki::Plugin::postsparkline::formula::$formula(\\\%params, \@list)}; if ($@) { -- cgit v1.2.3 From 332821144b33f42b3674240d28159124ee1a5334 Mon Sep 17 00:00:00 2001 From: Joey Hess Date: Thu, 8 Oct 2009 23:24:03 -0400 Subject: calendar: rework so it can use use_pagespec This was tricky because of the caching, and because use_pagespec always adds a dependency. That would have made year calendars depend on the whole pagespec, which is overly broad. So I removed the caching, format_month, and in format_year just look at %pagesources to see if month pages are available. In format_month, I make it always call use_pagespec, so each month calendar gets the right dependency and any influcences added. This means a bit more work, but the added work is fairly minimal, and presence dependencies remove a *lot* of work it used to do. (100% untested!) --- IkiWiki/Plugin/calendar.pm | 65 ++++++++++++++++++++-------------------------- 1 file changed, 28 insertions(+), 37 deletions(-) diff --git a/IkiWiki/Plugin/calendar.pm b/IkiWiki/Plugin/calendar.pm index c99170f92..a89175cfb 100644 --- a/IkiWiki/Plugin/calendar.pm +++ b/IkiWiki/Plugin/calendar.pm @@ -24,8 +24,6 @@ use IkiWiki 3.00; use Time::Local; use POSIX; -my %cache; -my %linkcache; my $time=time; my @now=localtime($time); @@ -75,6 +73,23 @@ sub format_month (@) { my $pyear = $params{pyear}; my $nyear = $params{nyear}; + my %linkcache; + foreach my $p (use_pagespec($params{page}, $params{pagespec}, + # add presence dependencies to update + # month calendar when pages are added/removed + deptype => deptype("presence"))) { + my $mtime = $IkiWiki::pagectime{$p}; + my $src = $pagesources{$p}; + my @date = localtime($mtime); + my $mday = $date[3]; + my $month = $date[4] + 1; + my $year = $date[5] + 1900; + my $mtag = sprintf("%02d", $month); + + # Only one posting per day is being linked to. + $linkcache{"$year/$mtag/$mday"} = "$src"; + } + my @list; my $calendar="\n"; @@ -99,21 +114,21 @@ sub format_month (@) { # Calculate URL's for monthly archives. my ($url, $purl, $nurl)=("$monthname",'',''); - if (exists $cache{$pagespec}{"$year/$month"}) { + if (exists $pagesources{"$archivebase/$year/$month"}) { $url = htmllink($params{page}, $params{destpage}, "$archivebase/$year/".sprintf("%02d", $month), linktext => " $monthname "); } add_depends($params{page}, "$archivebase/$year/".sprintf("%02d", $month), deptype("presence")); - if (exists $cache{$pagespec}{"$pyear/$pmonth"}) { + if (exists $pagesources{"$archivebase/$pyear/$pmonth"}) { $purl = htmllink($params{page}, $params{destpage}, "$archivebase/$pyear/" . sprintf("%02d", $pmonth), linktext => " $pmonthname "); } add_depends($params{page}, "$archivebase/$pyear/".sprintf("%02d", $pmonth), deptype("presence")); - if (exists $cache{$pagespec}{"$nyear/$nmonth"}) { + if (exists $pagesources{"$archivebase/$nyear/$nmonth"}) { $nurl = htmllink($params{page}, $params{destpage}, "$archivebase/$nyear/" . sprintf("%02d", $nmonth), linktext => " $nmonthname "); @@ -173,7 +188,7 @@ EOF my $tag; my $mtag = sprintf("%02d", $month); - if (defined $cache{$pagespec}{"$year/$mtag/$day"}) { + if (defined $pagesources{"$archivebase/$year/$mtag/$day"}) { if ($day == $today) { $tag='month-calendar-day-this-day'; } @@ -210,10 +225,6 @@ EOF EOF - # Add dependencies to update the calendar whenever pages - # matching the pagespec are added or removed. - add_depends($params{page}, $params{pages}, deptype("presence")); - return $calendar; } @@ -239,19 +250,19 @@ sub format_year (@) { # calculate URL's for previous and next years my ($url, $purl, $nurl)=("$year",'',''); - if (exists $cache{$pagespec}{"$year"}) { + if (exists $pagesources{"$archivebase/$year"}) { $url = htmllink($params{page}, $params{destpage}, "$archivebase/$year", linktext => "$year"); } - add_depends($params{page}, "$archivebase/$year", deptype("presence"); - if (exists $cache{$pagespec}{"$pyear"}) { + add_depends($params{page}, "$archivebase/$year", deptype("presence")); + if (exists $pagesources{"$archivebase/$pyear"}) { $purl = htmllink($params{page}, $params{destpage}, "$archivebase/$pyear", linktext => "\←"); } add_depends($params{page}, "$archivebase/$pyear", deptype("presence")); - if (exists $cache{$pagespec}{"$nyear"}) { + if (exists $pagesources{"$archivebase/$nyear"}) { $nurl = htmllink($params{page}, $params{destpage}, "$archivebase/$nyear", linktext => "\→"); @@ -280,14 +291,14 @@ EOF my $tag; my $mtag=sprintf("%02d", $month); if ($month == $params{month}) { - if ($cache{$pagespec}{"$year/$mtag"}) { + if ($pagesources{"$archivebase/$year/$mtag"}) { $tag = 'this_month_link'; } else { $tag = 'this_month_nolink'; } } - elsif ($cache{$pagespec}{"$year/$mtag"}) { + elsif ($pagesources{"$archivebase/$year/$mtag"}) { $tag = 'month_link'; } elsif ($future_month && $month >= $future_month) { @@ -297,7 +308,7 @@ EOF $tag = 'month_nolink'; } - if ($cache{$pagespec}{"$year/$mtag"}) { + if ($pagesources{"$archivebase/$year/$mtag"}) { $murl = htmllink($params{page}, $params{destpage}, "$archivebase/$year/$mtag", linktext => "$monthabbr"); @@ -366,26 +377,6 @@ sub preprocess (@) { $params{nyear} =$nyear; my $calendar="\n"; - my $pagespec=$params{pages}; - my $page =$params{page}; - - if (! defined $cache{$pagespec}) { - foreach my $p (pagespec_match_list([keys %pagesources], $pagespec)) { - my $mtime = $IkiWiki::pagectime{$p}; - my $src = $pagesources{$p}; - my @date = localtime($mtime); - my $mday = $date[3]; - my $month = $date[4] + 1; - my $year = $date[5] + 1900; - my $mtag = sprintf("%02d", $month); - - # Only one posting per day is being linked to. - $linkcache{"$year/$mtag/$mday"} = "$src"; - $cache{$pagespec}{"$year"}++; - $cache{$pagespec}{"$year/$mtag"}++; - $cache{$pagespec}{"$year/$mtag/$mday"}++; - } - } if ($params{type} =~ /month/i) { $calendar=format_month(%params); -- cgit v1.2.3 From 955bcea2a7bacb98cb62a38faa78b05e0f430aac Mon Sep 17 00:00:00 2001 From: Joey Hess Date: Thu, 8 Oct 2009 23:48:08 -0400 Subject: fix test broken by change to failing link() influence --- t/pagespec_match.t | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/t/pagespec_match.t b/t/pagespec_match.t index 36fa04370..ab3fcdd4b 100755 --- a/t/pagespec_match.t +++ b/t/pagespec_match.t @@ -103,9 +103,9 @@ is(join(",", keys %i), 'foo', "backlink is influenced by the page with the link" is(join(",", keys %i), 'foo', "created_before is influenced by the comparison page"); %i=pagespec_match("bar", "created_after(foo)")->influences; is(join(",", keys %i), 'foo', "created_after is influenced by the comparison page"); -%i=pagespec_match("bar", "link(quux) and created_after(foo)")->influences; +%i=pagespec_match("foo", "link(baz) and created_after(bar)")->influences; is(join(",", sort keys %i), 'bar,foo', "influences add up over AND"); -%i=pagespec_match("bar", "link(quux) and created_after(foo)")->influences; +%i=pagespec_match("foo", "link(baz) and created_after(bar)")->influences; is(join(",", sort keys %i), 'bar,foo', "influences add up over OR"); -%i=pagespec_match("bar", "!link(quux) and !created_after(foo)")->influences; +%i=pagespec_match("foo", "!link(baz) and !created_after(bar)")->influences; is(join(",", sort keys %i), 'bar,foo', "influences unaffected by negation"); -- cgit v1.2.3 From 5e7b2dea84a35163b599b88efc02cd7ef3e0ad46 Mon Sep 17 00:00:00 2001 From: Joey Hess Date: Thu, 8 Oct 2009 23:51:06 -0400 Subject: rename use_pagespec to pagespec_match_list To avoid breaking plugins, also support the old pagespec_match_list calling convention, with a deprecation warning. --- IkiWiki.pm | 183 ++++++++++++++++++---------------------- IkiWiki/Plugin/calendar.pm | 2 +- IkiWiki/Plugin/inline.pm | 8 +- IkiWiki/Plugin/map.pm | 3 +- IkiWiki/Plugin/orphans.pm | 2 +- IkiWiki/Plugin/pagecount.pm | 2 +- IkiWiki/Plugin/pagestats.pm | 9 +- IkiWiki/Plugin/postsparkline.pm | 2 +- debian/changelog | 6 +- doc/plugins/write.mdwn | 24 ++---- t/pagespec_match_list.t | 31 +++++++ t/use_pagespec.t | 31 ------- 12 files changed, 140 insertions(+), 163 deletions(-) create mode 100755 t/pagespec_match_list.t delete mode 100755 t/use_pagespec.t diff --git a/IkiWiki.pm b/IkiWiki.pm index daa71059b..fd7e23524 100644 --- a/IkiWiki.pm +++ b/IkiWiki.pm @@ -17,7 +17,7 @@ use vars qw{%config %links %oldlinks %pagemtime %pagectime %pagecase %forcerebuild %loaded_plugins}; use Exporter q{import}; -our @EXPORT = qw(hook debug error template htmlpage deptype use_pagespec +our @EXPORT = qw(hook debug error template htmlpage deptype add_depends pagespec_match pagespec_match_list bestlink htmllink readfile writefile pagetype srcfile pagename displaytime will_render gettext urlto targetpage @@ -1798,91 +1798,6 @@ sub add_depends ($$;$) { 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)) - if $firstfail->isa("IkiWiki::ErrorReason"); - } - - return @ret; -} - sub deptype (@) { my $deptype=0; foreach my $type (@_) { @@ -2055,27 +1970,95 @@ sub pagespec_match ($$;@) { } sub pagespec_match_list ($$;@) { - my $pages=shift; - my $spec=shift; - my @params=@_; + my $page=shift; + my $pagespec=shift; + my %params=@_; - my $sub=pagespec_translate($spec); - error "syntax error in pagespec \"$spec\"" + # Backwards compatability with old calling convention. + if (ref $page) { + print STDERR "warning: a plugin (".caller().") is using pagespec_match_list in an obsolete way, and needs to be updated\n"; + $params{list}=$page; + $page=$params{location}; # ugh! + } + + 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 @ret; - my $r; - foreach my $page (@$pages) { - $r=$sub->($page, @params); - push @ret, $page if $r; + 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); - if (! @ret && defined $r && $r->isa("IkiWiki::ErrorReason")) { - error(sprintf(gettext("cannot match pages: %s"), $r)); + 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}; + } + } } - else { - return @ret; + 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)) + if $firstfail->isa("IkiWiki::ErrorReason"); } + + return @ret; } sub pagespec_valid ($) { diff --git a/IkiWiki/Plugin/calendar.pm b/IkiWiki/Plugin/calendar.pm index a89175cfb..c50d038df 100644 --- a/IkiWiki/Plugin/calendar.pm +++ b/IkiWiki/Plugin/calendar.pm @@ -74,7 +74,7 @@ sub format_month (@) { my $nyear = $params{nyear}; my %linkcache; - foreach my $p (use_pagespec($params{page}, $params{pagespec}, + foreach my $p (pagespec_match_list($params{page}, $params{pagespec}, # add presence dependencies to update # month calendar when pages are added/removed deptype => deptype("presence"))) { diff --git a/IkiWiki/Plugin/inline.pm b/IkiWiki/Plugin/inline.pm index c02137aed..815a37838 100644 --- a/IkiWiki/Plugin/inline.pm +++ b/IkiWiki/Plugin/inline.pm @@ -216,7 +216,7 @@ sub preprocess_inline (@) { $num+=$params{skip}; } - @list = use_pagespec($params{page}, $params{pages}, + @list = pagespec_match_list($params{page}, $params{pages}, deptype => deptype($quick ? "presence" : "content"), limit => sub { $_[0] ne $params{page} }, sort => exists $params{sort} ? $params{sort} : "age", @@ -245,9 +245,11 @@ sub preprocess_inline (@) { } if ($feeds && exists $params{feedpages}) { - @feedlist = use_pagespec($params{page}, "($params{pages}) and ($params{feedpages})", + @feedlist = pagespec_match_list( + $params{page}, "($params{pages}) and ($params{feedpages})", deptype => deptype($quick ? "presence" : "content"), - list => \@feedlist); + list => \@feedlist, + ); } my ($feedbase, $feednum); diff --git a/IkiWiki/Plugin/map.pm b/IkiWiki/Plugin/map.pm index 634b0e4d6..788b96827 100644 --- a/IkiWiki/Plugin/map.pm +++ b/IkiWiki/Plugin/map.pm @@ -36,7 +36,8 @@ sub preprocess (@) { # Get all the items to map. my %mapitems; - foreach my $page (use_pagespec($params{page}, $params{pages}, deptype => $deptype)) { + foreach my $page (pagespec_match_list($params{page}, $params{pages}, + deptype => $deptype)) { if (exists $params{show} && exists $pagestate{$page} && exists $pagestate{$page}{meta}{$params{show}}) { diff --git a/IkiWiki/Plugin/orphans.pm b/IkiWiki/Plugin/orphans.pm index 607239500..b1ebd1b9d 100644 --- a/IkiWiki/Plugin/orphans.pm +++ b/IkiWiki/Plugin/orphans.pm @@ -28,7 +28,7 @@ sub preprocess (@) { # considering as orphans. add_depends($params{page}, "*", deptype("links")); - my @orphans=use_pagespec($params{page}, $params{pages}, + my @orphans=pagespec_match_list($params{page}, $params{pages}, # update when orphans are added/removed deptype => deptype("presence"), limit => sub { diff --git a/IkiWiki/Plugin/pagecount.pm b/IkiWiki/Plugin/pagecount.pm index 40474b2a1..8d36f057e 100644 --- a/IkiWiki/Plugin/pagecount.pm +++ b/IkiWiki/Plugin/pagecount.pm @@ -32,7 +32,7 @@ sub preprocess (@) { return scalar keys %pagesources; } - return scalar use_pagespec($params{page}, $pages, + return scalar pagespec_match_list($params{page}, $pages, deptype => deptype("presence")); } diff --git a/IkiWiki/Plugin/pagestats.pm b/IkiWiki/Plugin/pagestats.pm index e64f7d9c3..47638210a 100644 --- a/IkiWiki/Plugin/pagestats.pm +++ b/IkiWiki/Plugin/pagestats.pm @@ -37,16 +37,17 @@ sub preprocess (@) { my %counts; my $max = 0; - foreach my $page (use_pagespec($params{page}, $params{pages}, - # update when a displayed page is added or removed - deptype => deptype("presence"))) { + foreach my $page (pagespec_match_list($params{page}, $params{pages}, + # update when a displayed page is added/removed + deptype => deptype("presence"))) { use IkiWiki::Render; my @backlinks = IkiWiki::backlink_pages($page); if (exists $params{among}) { # only consider backlinks from the amoung pages - @backlinks = use_pagespec($params{page}, $params{among}, + @backlinks = pagespec_match_list( + $params{page}, $params{among}, # update whenever links on those pages change deptype => deptype("links"), list => \@backlinks diff --git a/IkiWiki/Plugin/postsparkline.pm b/IkiWiki/Plugin/postsparkline.pm index f51e309c8..1d4532366 100644 --- a/IkiWiki/Plugin/postsparkline.pm +++ b/IkiWiki/Plugin/postsparkline.pm @@ -54,7 +54,7 @@ sub preprocess (@) { } my @list=sort { $params{timehash}->{$b} <=> $params{timehash}->{$a} } - use_pagespec($params{page}, $params{pages}, + pagespec_match_list($params{page}, $params{pages}, deptype => $deptype, limit => sub { $_[0] ne $params{page} }, ); diff --git a/debian/changelog b/debian/changelog index 3a6fdf77d..49809e6cf 100644 --- a/debian/changelog +++ b/debian/changelog @@ -33,9 +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. + * API change: `pagespec_match_list` has completly changed its interface. + The old interface will be removed soon, and a warning will be printed + if any plugins try to use it. * Optimize away most expensive file prune calls, when refreshing, by only checking new files. diff --git a/doc/plugins/write.mdwn b/doc/plugins/write.mdwn index 62bebbeed..f6ea76c36 100644 --- a/doc/plugins/write.mdwn +++ b/doc/plugins/write.mdwn @@ -625,16 +625,16 @@ dependency type from one or more of these keywords: If multiple types are specified, they are combined. -#### `use_pagespec($$;@)` +#### `pagespec_match_list($$;@)` 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. +is significantly more efficient than calling `add_depends` and +`pagespec_match` in a loop. You should use this anytime a plugin +needs to match a set of pages and do something based on that list. Additional named parameters can be specified: @@ -650,6 +650,9 @@ Additional named parameters can be specified: * `list` makes it only match amoung the specified list of pages. Default is to match amoung all pages in the wiki. +Unlike pagespec_match, this may throw an error if there is an error in +the pagespec. + #### `add_depends($$;$)` Makes the specified page depend on the specified [[ikiwiki/PageSpec]]. @@ -672,19 +675,6 @@ 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. -#### `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 diff --git a/t/pagespec_match_list.t b/t/pagespec_match_list.t new file mode 100755 index 000000000..85a30b542 --- /dev/null +++ b/t/pagespec_match_list.t @@ -0,0 +1,31 @@ +#!/usr/bin/perl +use warnings; +use strict; +use Test::More tests => 10; + +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([pagespec_match_list("foo", "bar")], ["bar"]); +is_deeply([sort(pagespec_match_list("foo", "post/*"))], ["post/1", "post/2", "post/3"]); +is_deeply([pagespec_match_list("foo", "post/*", sort => "title", reverse => 1)], + ["post/3", "post/2", "post/1"]); +is_deeply([pagespec_match_list("foo", "post/*", sort => "title", num => 2)], + ["post/1", "post/2"]); +is_deeply([pagespec_match_list("foo", "post/*", sort => "title", num => 50)], + ["post/1", "post/2", "post/3"]); +is_deeply([pagespec_match_list("foo", "post/*", sort => "title", + limit => sub { $_[0] !~ /3/}) ], + ["post/1", "post/2"]); +my $r=eval { pagespec_match_list("foo", "beep") }; +ok(eval { pagespec_match_list("foo", "beep") } == 0); +ok(! $@, "does not fail with error when unable to match anything"); +eval { pagespec_match_list("foo", "this is not a legal pagespec!") }; +ok($@, "fails with error when pagespec bad"); diff --git a/t/use_pagespec.t b/t/use_pagespec.t deleted file mode 100755 index 92d7977cf..000000000 --- a/t/use_pagespec.t +++ /dev/null @@ -1,31 +0,0 @@ -#!/usr/bin/perl -use warnings; -use strict; -use Test::More tests => 10; - -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"]); -my $r=eval { use_pagespec("foo", "beep") }; -ok(eval { use_pagespec("foo", "beep") } == 0); -ok(! $@, "does not fail with error when unable to match anything"); -eval { use_pagespec("foo", "this is not a legal pagespec!") }; -ok($@, "fails with error when pagespec bad"); -- cgit v1.2.3 From c11b3af189059efc91d28cda7e8c5a893d004cb2 Mon Sep 17 00:00:00 2001 From: Joey Hess Date: Thu, 8 Oct 2009 23:55:50 -0400 Subject: typo --- debian/changelog | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/debian/changelog b/debian/changelog index 49809e6cf..5ff8e4ac5 100644 --- a/debian/changelog +++ b/debian/changelog @@ -36,7 +36,7 @@ ikiwiki (3.14159266) UNRELEASED; urgency=low * API change: `pagespec_match_list` has completly changed its interface. The old interface will be removed soon, and a warning will be printed if any plugins try to use it. - * Optimize away most expensive file prune calls, when refreshing, + * Optimize away most expensive file prune checks, when refreshing, by only checking new files. -- Joey Hess Sun, 27 Sep 2009 17:40:03 -0400 -- cgit v1.2.3 From fb3fd6b60fb584d8c1c0f76253d53633127afb18 Mon Sep 17 00:00:00 2001 From: Joey Hess Date: Fri, 9 Oct 2009 00:06:08 -0400 Subject: don't link to inline, not available when directives underlay is not enabled --- doc/ikiwiki/pagespec/sorting.mdwn | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/ikiwiki/pagespec/sorting.mdwn b/doc/ikiwiki/pagespec/sorting.mdwn index 1e0366029..41aa58151 100644 --- a/doc/ikiwiki/pagespec/sorting.mdwn +++ b/doc/ikiwiki/pagespec/sorting.mdwn @@ -1,5 +1,5 @@ Some [[directives|ikiwiki/directive]] that use -[[PageSpecs|ikiwiki/pagespec]], such as [[ikiwiki/directive/inline]], allow +[[PageSpecs|ikiwiki/pagespec]] allow specifying the order that matching pages are shown in. The following sort orders can be specified. -- cgit v1.2.3 From fa82be552452ffcd554fcd6af5aa94ff3cf90ac5 Mon Sep 17 00:00:00 2001 From: Joey Hess Date: Fri, 9 Oct 2009 00:06:40 -0400 Subject: add pagespec/sorting to underlay --- underlays/basewiki/ikiwiki/pagespec/sorting.mdwn | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 underlays/basewiki/ikiwiki/pagespec/sorting.mdwn diff --git a/underlays/basewiki/ikiwiki/pagespec/sorting.mdwn b/underlays/basewiki/ikiwiki/pagespec/sorting.mdwn new file mode 100644 index 000000000..41aa58151 --- /dev/null +++ b/underlays/basewiki/ikiwiki/pagespec/sorting.mdwn @@ -0,0 +1,11 @@ +Some [[directives|ikiwiki/directive]] that use +[[PageSpecs|ikiwiki/pagespec]] allow +specifying the order that matching pages are shown in. The following sort +orders can be specified. + +* `age` - List pages from the most recently created to the oldest. +* `mtime` - List pages with the most recently modified first. +* `title` - Order by title. +* `title_natural` - Only available if [[!cpan Sort::Naturally]] is + installed. Orders by title, but numbers in the title are treated + as such, ("1 2 9 10 20" instead of "1 10 2 20 9") -- cgit v1.2.3 From 34b213235529300c8be19290cefb1e5a01e2da3a Mon Sep 17 00:00:00 2001 From: Joey Hess Date: Fri, 9 Oct 2009 00:06:58 -0400 Subject: fix test to use new calling convention This test still fails several cases, since add_depends influence testing is currently commented out. --- t/add_depends.t | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/t/add_depends.t b/t/add_depends.t index 9f426187b..fce7a76c6 100755 --- a/t/add_depends.t +++ b/t/add_depends.t @@ -31,15 +31,15 @@ ok($IkiWiki::depends_simple{foo0}{"bar"} & $IkiWiki::DEPEND_CONTENT); ok(! ($IkiWiki::depends_simple{foo0}{"bar"} & ($IkiWiki::DEPEND_PRESENCE | $IkiWiki::DEPEND_LINKS))); # adding other dep types standalone -ok(add_depends("foo2", "*", presence => 1)); -ok(add_depends("foo2", "bar", links => 1)); +ok(add_depends("foo2", "*", deptype("presence"))); +ok(add_depends("foo2", "bar", deptype("links"))); ok($IkiWiki::depends{foo2}{"*"} & $IkiWiki::DEPEND_PRESENCE); ok(! ($IkiWiki::depends{foo2}{"*"} & ($IkiWiki::DEPEND_CONTENT | $IkiWiki::DEPEND_LINKS))); ok($IkiWiki::depends_simple{foo2}{"bar"} & $IkiWiki::DEPEND_LINKS); ok(! ($IkiWiki::depends_simple{foo2}{"bar"} & ($IkiWiki::DEPEND_PRESENCE | $IkiWiki::DEPEND_CONTENT))); # adding combined dep types -ok(add_depends("foo2", "baz", links => 1, presence => 1)); +ok(add_depends("foo2", "baz", deptype("links". "presence"))); ok($IkiWiki::depends_simple{foo2}{"baz"} & $IkiWiki::DEPEND_LINKS); ok($IkiWiki::depends_simple{foo2}{"baz"} & $IkiWiki::DEPEND_PRESENCE); ok(! ($IkiWiki::depends_simple{foo2}{"baz"} & $IkiWiki::DEPEND_CONTENT)); @@ -49,10 +49,10 @@ ok(add_depends("foo2", "baz")); ok($IkiWiki::depends_simple{foo2}{"baz"} & $IkiWiki::DEPEND_LINKS); ok($IkiWiki::depends_simple{foo2}{"baz"} & $IkiWiki::DEPEND_PRESENCE); ok(($IkiWiki::depends_simple{foo2}{"baz"} & $IkiWiki::DEPEND_CONTENT)); -ok(add_depends("foo2", "bar", presence => 1)); # had only links before +ok(add_depends("foo2", "bar", deptype("presence"))); # had only links before ok($IkiWiki::depends_simple{foo2}{"bar"} & ($IkiWiki::DEPEND_LINKS | $IkiWiki::DEPEND_PRESENCE)); ok(! ($IkiWiki::depends_simple{foo2}{"bar"} & $IkiWiki::DEPEND_CONTENT)); -ok(add_depends("foo0", "bar", links => 1)); # had only content before +ok(add_depends("foo0", "bar", deptype("links"))); # had only content before ok($IkiWiki::depends{foo0}{"*"} & ($IkiWiki::DEPEND_CONTENT | $IkiWiki::DEPEND_LINKS)); ok(! ($IkiWiki::depends{foo0}{"*"} & $IkiWiki::DEPEND_PRESENCE)); @@ -60,11 +60,11 @@ ok(! ($IkiWiki::depends{foo0}{"*"} & $IkiWiki::DEPEND_PRESENCE)); # as an explicit dependency. In the case of a link, a links dependency. $links{foo0}=$links{foo9}=[qw{bar baz}]; foreach my $spec ("* and ! link(bar)", "* or link(bar)") { - ok(add_depends("foo3", $spec, presence => 1)); + ok(add_depends("foo3", $spec, deptype("presence"))); ok($IkiWiki::depends{foo3}{$spec} & $IkiWiki::DEPEND_PRESENCE); ok(! ($IkiWiki::depends{foo3}{$spec} & ($IkiWiki::DEPEND_CONTENT | $IkiWiki::DEPEND_LINKS))); ok($IkiWiki::depends_simple{foo3}{foo3} == $IkiWiki::DEPEND_LINKS); - ok(add_depends("foo4", $spec, links => 1)); + ok(add_depends("foo4", $spec, deptype("links"))); ok($IkiWiki::depends{foo4}{$spec} & $IkiWiki::DEPEND_LINKS); ok(! ($IkiWiki::depends{foo4}{$spec} & ($IkiWiki::DEPEND_CONTENT | $IkiWiki::DEPEND_PRESENCE))); ok($IkiWiki::depends_simple{foo4}{foo4} == $IkiWiki::DEPEND_LINKS); @@ -73,15 +73,15 @@ foreach my $spec ("* and ! link(bar)", "* or link(bar)") { # a pagespec with backlinks() will add as an influence the page with the links $links{foo0}=[qw{foo5 foo7}]; foreach my $spec ("bugs or (backlink(foo0) and !*.png)", "backlink(foo)") { - ok(add_depends("foo5", $spec, presence => 1)); + ok(add_depends("foo5", $spec, deptype("presence"))); ok($IkiWiki::depends{foo5}{$spec} & $IkiWiki::DEPEND_PRESENCE); ok(! ($IkiWiki::depends{foo5}{$spec} & ($IkiWiki::DEPEND_CONTENT | $IkiWiki::DEPEND_LINKS))); ok($IkiWiki::depends_simple{foo5}{foo0} == $IkiWiki::DEPEND_LINKS); - ok(add_depends("foo6", $spec, links => 1)); + ok(add_depends("foo6", $spec, deptype("links"))); ok($IkiWiki::depends{foo6}{$spec} & $IkiWiki::DEPEND_LINKS); ok(! ($IkiWiki::depends{foo6}{$spec} & ($IkiWiki::DEPEND_PRESENCE | $IkiWiki::DEPEND_CONTENT))); ok($IkiWiki::depends_simple{foo5}{foo0} == $IkiWiki::DEPEND_LINKS); - ok(add_depends("foo7", $spec, presence => 1, links => 1)); + ok(add_depends("foo7", $spec, deptype("presence", "links"))); ok($IkiWiki::depends{foo7}{$spec} & $IkiWiki::DEPEND_PRESENCE); ok($IkiWiki::depends{foo7}{$spec} & $IkiWiki::DEPEND_LINKS); ok(! ($IkiWiki::depends{foo7}{$spec} & $IkiWiki::DEPEND_CONTENT)); @@ -93,6 +93,6 @@ foreach my $spec ("bugs or (backlink(foo0) and !*.png)", "backlink(foo)") { } # content is the default if unknown types are entered -ok(add_depends("foo9", "*", presenCe => 1)); +ok(add_depends("foo9", "*", deptype("monkey"))); ok($IkiWiki::depends{foo9}{"*"} & $IkiWiki::DEPEND_CONTENT); ok(! ($IkiWiki::depends{foo9}{"*"} & ($IkiWiki::DEPEND_PRESENCE | $IkiWiki::DEPEND_LINKS))); -- cgit v1.2.3 From c791f84fb54c723e3bb488a5099e435a64d1c8b0 Mon Sep 17 00:00:00 2001 From: Joey Hess Date: Fri, 9 Oct 2009 12:35:41 -0400 Subject: linkmap: Use new pagespec_match_list --- IkiWiki/Plugin/linkmap.pm | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/IkiWiki/Plugin/linkmap.pm b/IkiWiki/Plugin/linkmap.pm index 28e4cfa13..9540bd112 100644 --- a/IkiWiki/Plugin/linkmap.pm +++ b/IkiWiki/Plugin/linkmap.pm @@ -28,10 +28,6 @@ sub preprocess (@) { $params{pages}="*" unless defined $params{pages}; - # Needs to update whenever a relevant page is added, or removed, or - # its links change. - add_depends($params{page}, $params{pages}, deptype("presence", "links")); - # Can't just return the linkmap here, since the htmlscrubber # scrubs out all tags (with good reason!) # Instead, insert a placeholder tag, which will be expanded during @@ -55,12 +51,11 @@ sub genmap ($) { my %params=%{$maps{$mapnum}}; # Get all the items to map. - my %mapitems = (); - foreach my $item (keys %pagesources) { - if (pagespec_match($item, $params{pages}, location => $params{page})) { - $mapitems{$item}=urlto($item, $params{destpage}); - } - } + my %mapitems = map { $_ => urlto($_, $params{destpage}) } + pagespec_match_list($params{page}, $params{pages}, + # update when a page is added or removed, or its + # links change + deptype => deptype("presence", "links")); my $dest=$params{page}."/linkmap.png"; -- cgit v1.2.3 From 96682e3084993428f4de384f5087cffdc29f1710 Mon Sep 17 00:00:00 2001 From: Joey Hess Date: Fri, 9 Oct 2009 12:48:16 -0400 Subject: progress: switch to new pagespec_match_list --- IkiWiki/Plugin/progress.pm | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/IkiWiki/Plugin/progress.pm b/IkiWiki/Plugin/progress.pm index 6da3e4f71..fe64b40b1 100644 --- a/IkiWiki/Plugin/progress.pm +++ b/IkiWiki/Plugin/progress.pm @@ -36,16 +36,12 @@ sub preprocess (@) { $fill.="%"; } elsif (defined $params{totalpages} and defined $params{donepages}) { - add_depends($params{page}, $params{totalpages}, deptype("presence")); - add_depends($params{page}, $params{donepages}, deptype("presence")); - - my @pages=keys %pagesources; - my $totalcount=0; - my $donecount=0; - foreach my $page (@pages) { - $totalcount++ if pagespec_match($page, $params{totalpages}, location => $params{page}); - $donecount++ if pagespec_match($page, $params{donepages}, location => $params{page}); - } + my $totalcount=pagespec_match_list( + $params{page}, $params{totalpages}, + deptype => deptype("presence")); + my $donecount=pagespec_match_list( + $params{page}, $params{donepages}, + deptype => deptype("presence")); if ($totalcount == 0) { $fill = "100%"; -- cgit v1.2.3 From b7351daacd0d4a041a51b43d99b7bf589de54f53 Mon Sep 17 00:00:00 2001 From: Joey Hess Date: Fri, 9 Oct 2009 12:54:13 -0400 Subject: conditional: use yesno --- IkiWiki.pm | 2 +- IkiWiki/Plugin/conditional.pm | 2 +- t/yesno.t | 4 +++- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/IkiWiki.pm b/IkiWiki.pm index fd7e23524..475e278c3 100644 --- a/IkiWiki.pm +++ b/IkiWiki.pm @@ -1792,7 +1792,7 @@ sub add_depends ($$;$) { # $depends_simple{$page}{lc $i} |= $i{$i}; # } #} - print STDERR "warning: use of add_depends; influences not tracked\n"; + print STDERR "warning: use of add_depends by ".caller()."; influences not tracked\n"; $depends{$page}{$pagespec} |= $deptype; return 1; diff --git a/IkiWiki/Plugin/conditional.pm b/IkiWiki/Plugin/conditional.pm index 7445dbdad..7ead701f2 100644 --- a/IkiWiki/Plugin/conditional.pm +++ b/IkiWiki/Plugin/conditional.pm @@ -29,7 +29,7 @@ sub preprocess_if (@) { } my $result=0; - if ((exists $params{all} && lc $params{all} eq "no") || + if (! IkiWiki::yesno($params{all}) || # An optimisation to avoid needless looping over every page # and adding of dependencies for simple uses of some of the # tests. diff --git a/t/yesno.t b/t/yesno.t index 60a8c071d..8770390a1 100755 --- a/t/yesno.t +++ b/t/yesno.t @@ -1,7 +1,7 @@ #!/usr/bin/perl use warnings; use strict; -use Test::More tests => 10; +use Test::More tests => 11; BEGIN { use_ok("IkiWiki"); } @@ -19,3 +19,5 @@ ok(IkiWiki::yesno("NO") == 0); ok(IkiWiki::yesno("1") == 1); ok(IkiWiki::yesno("0") == 0); ok(IkiWiki::yesno("mooooooooooo") == 0); + +ok(IkiWiki::yesno(undef) == 0); -- cgit v1.2.3 From c7da9911580e9311981758922d354aea03b8074c Mon Sep 17 00:00:00 2001 From: Joey Hess Date: Fri, 9 Oct 2009 13:02:03 -0400 Subject: indentation --- IkiWiki/Plugin/conditional.pm | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/IkiWiki/Plugin/conditional.pm b/IkiWiki/Plugin/conditional.pm index 7ead701f2..bc7b8974d 100644 --- a/IkiWiki/Plugin/conditional.pm +++ b/IkiWiki/Plugin/conditional.pm @@ -30,10 +30,10 @@ sub preprocess_if (@) { my $result=0; if (! IkiWiki::yesno($params{all}) || - # An optimisation to avoid needless looping over every page - # and adding of dependencies for simple uses of some of the - # tests. - $params{test} =~ /^([\s\!()]*((enabled|sourcepage|destpage|included)\([^)]*\)|(and|or))[\s\!()]*)+$/) { + # An optimisation to avoid needless looping over every page + # and adding of dependencies for simple uses of some of the + # tests. + $params{test} =~ /^([\s\!()]*((enabled|sourcepage|destpage|included)\([^)]*\)|(and|or))[\s\!()]*)+$/) { add_depends($params{page}, "($params{test}) and $params{page}"); $result=pagespec_match($params{page}, $params{test}, location => $params{page}, -- cgit v1.2.3 From 769b78df078d0287a10166ce828941a491858ff2 Mon Sep 17 00:00:00 2001 From: Joey Hess Date: Fri, 9 Oct 2009 13:02:10 -0400 Subject: pagespec_match_list allow additional pagespec limit parameters again --- IkiWiki.pm | 12 ++++++++---- doc/plugins/write.mdwn | 7 +++++-- 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/IkiWiki.pm b/IkiWiki.pm index 475e278c3..f959d868b 100644 --- a/IkiWiki.pm +++ b/IkiWiki.pm @@ -2019,21 +2019,25 @@ sub pagespec_match_list ($$;@) { @candidates=reverse(@candidates) if $params{reverse}; + $depends{$page}{$pagespec} |= ($params{deptype} || $DEPEND_CONTENT); + + # clear params, remainder is passed to pagespec + my $num=$params{num}; + delete @params{qw{num deptype reverse sort limit}}; + my @matches; my $firstfail; my $count=0; foreach my $p (@candidates) { - my $r=$sub->($p, location => $page); + my $r=$sub->($p, %params, location => $page); if ($r) { push @matches, [$p, $r]; - last if defined $params{num} && ++$count == $params{num}; + last if defined $num && ++$count == $num; } elsif (! defined $firstfail) { $firstfail=$r; } } - - $depends{$page}{$pagespec} |= ($params{deptype} || $DEPEND_CONTENT); my @ret; if (@matches) { diff --git a/doc/plugins/write.mdwn b/doc/plugins/write.mdwn index f6ea76c36..9661bf4de 100644 --- a/doc/plugins/write.mdwn +++ b/doc/plugins/write.mdwn @@ -636,6 +636,9 @@ is significantly more efficient than calling `add_depends` and `pagespec_match` in a loop. You should use this anytime a plugin needs to match a set of pages and do something based on that list. +Unlike pagespec_match, this may throw an error if there is an error in +the pagespec. + Additional named parameters can be specified: * `deptype` optionally specifies the type of dependency to add. Use the @@ -650,8 +653,8 @@ Additional named parameters can be specified: * `list` makes it only match amoung the specified list of pages. Default is to match amoung all pages in the wiki. -Unlike pagespec_match, this may throw an error if there is an error in -the pagespec. +Any other named parameters are passed on to `pagespec_match`, to further +limit the match. #### `add_depends($$;$)` -- cgit v1.2.3 From f9f7a6e9f34b120504bb1dc238a3a627e9a8e3dc Mon Sep 17 00:00:00 2001 From: Joey Hess Date: Fri, 9 Oct 2009 13:07:50 -0400 Subject: conditional: use pagespec_match_list --- IkiWiki/Plugin/conditional.pm | 20 +++++++------------- 1 file changed, 7 insertions(+), 13 deletions(-) diff --git a/IkiWiki/Plugin/conditional.pm b/IkiWiki/Plugin/conditional.pm index bc7b8974d..aad617812 100644 --- a/IkiWiki/Plugin/conditional.pm +++ b/IkiWiki/Plugin/conditional.pm @@ -31,8 +31,7 @@ sub preprocess_if (@) { my $result=0; if (! IkiWiki::yesno($params{all}) || # An optimisation to avoid needless looping over every page - # and adding of dependencies for simple uses of some of the - # tests. + # for simple uses of some of the tests. $params{test} =~ /^([\s\!()]*((enabled|sourcepage|destpage|included)\([^)]*\)|(and|or))[\s\!()]*)+$/) { add_depends($params{page}, "($params{test}) and $params{page}"); $result=pagespec_match($params{page}, $params{test}, @@ -41,17 +40,12 @@ sub preprocess_if (@) { destpage => $params{destpage}); } else { - add_depends($params{page}, $params{test}); - - foreach my $page (keys %pagesources) { - if (pagespec_match($page, $params{test}, - location => $params{page}, - sourcepage => $params{page}, - destpage => $params{destpage})) { - $result=1; - last; - } - } + $result=pagespec_match_list($params{page}, $params{test}, + # stop after first match + num => 1, + sourcepage => $params{page}, + destpage => $params{destpage}, + ); } my $ret; -- cgit v1.2.3 From 6f2cc5ac8cc7e76b3faf20cd7516f82bcb3de7ed Mon Sep 17 00:00:00 2001 From: Joey Hess Date: Fri, 9 Oct 2009 13:20:41 -0400 Subject: pagespec_match_list: change limit to filter --- IkiWiki.pm | 6 +++--- IkiWiki/Plugin/inline.pm | 2 +- IkiWiki/Plugin/orphans.pm | 10 +++++----- IkiWiki/Plugin/postsparkline.pm | 2 +- doc/plugins/write.mdwn | 4 ++-- 5 files changed, 12 insertions(+), 12 deletions(-) diff --git a/IkiWiki.pm b/IkiWiki.pm index f959d868b..49c76c4d4 100644 --- a/IkiWiki.pm +++ b/IkiWiki.pm @@ -1986,8 +1986,8 @@ sub pagespec_match_list ($$;@) { if $@ || ! defined $sub; my @candidates; - if (exists $params{limit}) { - @candidates=grep { $params{limit}->($_) } keys %pagesources; + if (exists $params{filter}) { + @candidates=grep { ! $params{filter}->($_) } keys %pagesources; } else { @candidates=keys %pagesources; @@ -2023,7 +2023,7 @@ sub pagespec_match_list ($$;@) { # clear params, remainder is passed to pagespec my $num=$params{num}; - delete @params{qw{num deptype reverse sort limit}}; + delete @params{qw{num deptype reverse sort filter}}; my @matches; my $firstfail; diff --git a/IkiWiki/Plugin/inline.pm b/IkiWiki/Plugin/inline.pm index 815a37838..0fe0bd2e1 100644 --- a/IkiWiki/Plugin/inline.pm +++ b/IkiWiki/Plugin/inline.pm @@ -218,7 +218,7 @@ sub preprocess_inline (@) { @list = pagespec_match_list($params{page}, $params{pages}, deptype => deptype($quick ? "presence" : "content"), - limit => sub { $_[0] ne $params{page} }, + filter => sub { $_[0] eq $params{page} }, sort => exists $params{sort} ? $params{sort} : "age", reverse => yesno($params{reverse}), num => $num, diff --git a/IkiWiki/Plugin/orphans.pm b/IkiWiki/Plugin/orphans.pm index b1ebd1b9d..702943f87 100644 --- a/IkiWiki/Plugin/orphans.pm +++ b/IkiWiki/Plugin/orphans.pm @@ -31,24 +31,24 @@ sub preprocess (@) { my @orphans=pagespec_match_list($params{page}, $params{pages}, # update when orphans are added/removed deptype => deptype("presence"), - limit => sub { + filter => sub { my $page=shift; # Filter out pages that other pages link to. - return 0 if IkiWiki::backlink_pages($page); + return 1 if IkiWiki::backlink_pages($page); # Toplevel index is assumed to never be orphaned. - return 0 if $page eq 'index'; + return 1 if $page eq 'index'; # If the page has a link to some other page, it's # indirectly linked via that page's backlinks. - return 0 if grep { + return 1 if grep { length $_ && ($_ !~ /\/\Q$config{discussionpage}\E$/i || ! $config{discussion}) && bestlink($page, $_) !~ /^(\Q$page\E|)$/ } @{$links{$page}}; - return 1; + return 0; }, ); diff --git a/IkiWiki/Plugin/postsparkline.pm b/IkiWiki/Plugin/postsparkline.pm index 1d4532366..0d5a12e33 100644 --- a/IkiWiki/Plugin/postsparkline.pm +++ b/IkiWiki/Plugin/postsparkline.pm @@ -56,7 +56,7 @@ sub preprocess (@) { my @list=sort { $params{timehash}->{$b} <=> $params{timehash}->{$a} } pagespec_match_list($params{page}, $params{pages}, deptype => $deptype, - limit => sub { $_[0] ne $params{page} }, + filter => sub { $_[0] eq $params{page} }, ); my @data=eval qq{IkiWiki::Plugin::postsparkline::formula::$formula(\\\%params, \@list)}; diff --git a/doc/plugins/write.mdwn b/doc/plugins/write.mdwn index 9661bf4de..2254d7025 100644 --- a/doc/plugins/write.mdwn +++ b/doc/plugins/write.mdwn @@ -643,8 +643,8 @@ 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. +* `filter` is a reference to a function, that is called and passed a page, + and returns true if the page should be filtered out of the list. * `sort` specifies a sort order for the list. See [[ikiwiki/PageSpec/sorting]] for the avilable sort methods. * `reverse` if true, sorts in reverse. -- cgit v1.2.3 From 3807aa298cc3a6ad7fbb39c3ff13fd5916a5c469 Mon Sep 17 00:00:00 2001 From: Joey Hess Date: Fri, 9 Oct 2009 13:28:41 -0400 Subject: fix pagespec_match_list handling of list parameter --- IkiWiki.pm | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/IkiWiki.pm b/IkiWiki.pm index 49c76c4d4..232d3e77b 100644 --- a/IkiWiki.pm +++ b/IkiWiki.pm @@ -1986,11 +1986,15 @@ sub pagespec_match_list ($$;@) { if $@ || ! defined $sub; my @candidates; - if (exists $params{filter}) { - @candidates=grep { ! $params{filter}->($_) } keys %pagesources; + if (exists $params{list}) { + @candidates=exists $params{filter} + ? grep { ! $params{filter}->($_) } @{$params{list}} + : @{$params{list}}; } else { - @candidates=keys %pagesources; + @candidates=exists $params{filter} + ? grep { ! $params{filter}->($_) } keys %pagesources + : keys %pagesources; } if (defined $params{sort}) { @@ -2023,7 +2027,7 @@ sub pagespec_match_list ($$;@) { # clear params, remainder is passed to pagespec my $num=$params{num}; - delete @params{qw{num deptype reverse sort filter}}; + delete @params{qw{num deptype reverse sort filter list}}; my @matches; my $firstfail; -- cgit v1.2.3 From e0b0b57211e8fe609c09a37605a21f42a6d734d3 Mon Sep 17 00:00:00 2001 From: Joey Hess Date: Fri, 9 Oct 2009 13:33:49 -0400 Subject: fix link --- doc/translation.mdwn | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/translation.mdwn b/doc/translation.mdwn index d869a6821..9d874d98e 100644 --- a/doc/translation.mdwn +++ b/doc/translation.mdwn @@ -23,7 +23,7 @@ essentially three pieces needed for a complete translation: file, and in preprocessor directives. 1. The [[basewiki]] needs to be translated. The - [[plugins/contrib/po]] ikiwiki plugin will allow translating + [[plugins/po]] ikiwiki plugin will allow translating wikis using po files and can be used for this. There is now a website, [l10n.ikiwiki.info](http://l10n.ikiwiki.info) -- cgit v1.2.3 From 1b6b1ee2d8f2e148bca301b177713ca35d2b8691 Mon Sep 17 00:00:00 2001 From: Joey Hess Date: Fri, 9 Oct 2009 13:35:11 -0400 Subject: brokenlinks: use pagespec_match_list --- IkiWiki/Plugin/brokenlinks.pm | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/IkiWiki/Plugin/brokenlinks.pm b/IkiWiki/Plugin/brokenlinks.pm index 62a0a42f4..8ee734bf9 100644 --- a/IkiWiki/Plugin/brokenlinks.pm +++ b/IkiWiki/Plugin/brokenlinks.pm @@ -23,18 +23,15 @@ sub preprocess (@) { my %params=@_; $params{pages}="*" unless defined $params{pages}; - # Needs to update whenever the links on a page change. - add_depends($params{page}, $params{pages}, deptype("links")); - my @broken; foreach my $link (keys %IkiWiki::brokenlinks) { next if $link =~ /.*\/\Q$config{discussionpage}\E/i && $config{discussion}; - my @pages; - foreach my $page (@{$IkiWiki::brokenlinks{$link}}) { - push @pages, $page - if pagespec_match($page, $params{pages}, location => $params{page}); - } + my @pages=pagespec_match_list($params{page}, $params{pages}, + list => $IkiWiki::brokenlinks{$link}, + # needs to update when links on a page change + deptype => deptype("links") + ); next unless @pages; my $page=$IkiWiki::brokenlinks{$link}->[0]; -- cgit v1.2.3 From c5e237c0135e28f3399830abcbdae844d3006a84 Mon Sep 17 00:00:00 2001 From: Joey Hess Date: Fri, 9 Oct 2009 13:37:06 -0400 Subject: img: use presence dependency when linking to a page --- IkiWiki/Plugin/img.pm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/IkiWiki/Plugin/img.pm b/IkiWiki/Plugin/img.pm index e2f541506..32023fa97 100644 --- a/IkiWiki/Plugin/img.pm +++ b/IkiWiki/Plugin/img.pm @@ -170,7 +170,7 @@ sub preprocess (@) { my $b = bestlink($params{page}, $params{link}); if (length $b) { - add_depends($params{page}, $b); + add_depends($params{page}, $b, deptype("presence")); $imgtag=htmllink($params{page}, $params{destpage}, $params{link}, linktext => $imgtag, noimageinline => 1); -- cgit v1.2.3 From 9eb229bfc73066e5d12d5a199c77f63d5881dfb7 Mon Sep 17 00:00:00 2001 From: Joey Hess Date: Fri, 9 Oct 2009 14:05:22 -0400 Subject: move influence tests to pagespec_match_list.t --- t/add_depends.t | 36 ------------------------------ t/pagespec_match_list.t | 58 +++++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 56 insertions(+), 38 deletions(-) diff --git a/t/add_depends.t b/t/add_depends.t index fce7a76c6..e3f0b6603 100755 --- a/t/add_depends.t +++ b/t/add_depends.t @@ -56,42 +56,6 @@ ok(add_depends("foo0", "bar", deptype("links"))); # had only content before ok($IkiWiki::depends{foo0}{"*"} & ($IkiWiki::DEPEND_CONTENT | $IkiWiki::DEPEND_LINKS)); ok(! ($IkiWiki::depends{foo0}{"*"} & $IkiWiki::DEPEND_PRESENCE)); -# Adding a pagespec that requires page metadata should add the influence -# as an explicit dependency. In the case of a link, a links dependency. -$links{foo0}=$links{foo9}=[qw{bar baz}]; -foreach my $spec ("* and ! link(bar)", "* or link(bar)") { - ok(add_depends("foo3", $spec, deptype("presence"))); - ok($IkiWiki::depends{foo3}{$spec} & $IkiWiki::DEPEND_PRESENCE); - ok(! ($IkiWiki::depends{foo3}{$spec} & ($IkiWiki::DEPEND_CONTENT | $IkiWiki::DEPEND_LINKS))); - ok($IkiWiki::depends_simple{foo3}{foo3} == $IkiWiki::DEPEND_LINKS); - ok(add_depends("foo4", $spec, deptype("links"))); - ok($IkiWiki::depends{foo4}{$spec} & $IkiWiki::DEPEND_LINKS); - ok(! ($IkiWiki::depends{foo4}{$spec} & ($IkiWiki::DEPEND_CONTENT | $IkiWiki::DEPEND_PRESENCE))); - ok($IkiWiki::depends_simple{foo4}{foo4} == $IkiWiki::DEPEND_LINKS); -} - -# a pagespec with backlinks() will add as an influence the page with the links -$links{foo0}=[qw{foo5 foo7}]; -foreach my $spec ("bugs or (backlink(foo0) and !*.png)", "backlink(foo)") { - ok(add_depends("foo5", $spec, deptype("presence"))); - ok($IkiWiki::depends{foo5}{$spec} & $IkiWiki::DEPEND_PRESENCE); - ok(! ($IkiWiki::depends{foo5}{$spec} & ($IkiWiki::DEPEND_CONTENT | $IkiWiki::DEPEND_LINKS))); - ok($IkiWiki::depends_simple{foo5}{foo0} == $IkiWiki::DEPEND_LINKS); - ok(add_depends("foo6", $spec, deptype("links"))); - ok($IkiWiki::depends{foo6}{$spec} & $IkiWiki::DEPEND_LINKS); - ok(! ($IkiWiki::depends{foo6}{$spec} & ($IkiWiki::DEPEND_PRESENCE | $IkiWiki::DEPEND_CONTENT))); - ok($IkiWiki::depends_simple{foo5}{foo0} == $IkiWiki::DEPEND_LINKS); - ok(add_depends("foo7", $spec, deptype("presence", "links"))); - ok($IkiWiki::depends{foo7}{$spec} & $IkiWiki::DEPEND_PRESENCE); - ok($IkiWiki::depends{foo7}{$spec} & $IkiWiki::DEPEND_LINKS); - ok(! ($IkiWiki::depends{foo7}{$spec} & $IkiWiki::DEPEND_CONTENT)); - ok($IkiWiki::depends_simple{foo7}{foo0} == $IkiWiki::DEPEND_LINKS); - ok(add_depends("foo8", $spec)); - ok($IkiWiki::depends{foo8}{$spec} & $IkiWiki::DEPEND_CONTENT); - ok(! ($IkiWiki::depends{foo8}{$spec} & ($IkiWiki::DEPEND_PRESENCE | $IkiWiki::DEPEND_LINKS))); - ok($IkiWiki::depends_simple{foo8}{foo0} == $IkiWiki::DEPEND_LINKS); -} - # content is the default if unknown types are entered ok(add_depends("foo9", "*", deptype("monkey"))); ok($IkiWiki::depends{foo9}{"*"} & $IkiWiki::DEPEND_CONTENT); diff --git a/t/pagespec_match_list.t b/t/pagespec_match_list.t index 85a30b542..301197cc1 100755 --- a/t/pagespec_match_list.t +++ b/t/pagespec_match_list.t @@ -1,19 +1,29 @@ #!/usr/bin/perl use warnings; use strict; -use Test::More tests => 10; +use Test::More tests => 49; BEGIN { use_ok("IkiWiki"); } +%config=IkiWiki::defaultconfig(); +$config{srcdir}=$config{destdir}="/dev/null"; +IkiWiki::checkconfig(); + %pagesources=( foo => "foo.mdwn", + foo2 => "foo2.mdwn", + foo3 => "foo3.mdwn", bar => "bar.mdwn", "post/1" => "post/1.mdwn", "post/2" => "post/2.mdwn", "post/3" => "post/3.mdwn", ); +$links{foo}=[qw{post/1 post/2}]; +$links{foo2}=[qw{bar}]; +$links{foo3}=[qw{bar}]; is_deeply([pagespec_match_list("foo", "bar")], ["bar"]); +is_deeply([sort(pagespec_match_list("foo", "* and !post/*"))], ["bar", "foo", "foo2", "foo3"]); is_deeply([sort(pagespec_match_list("foo", "post/*"))], ["post/1", "post/2", "post/3"]); is_deeply([pagespec_match_list("foo", "post/*", sort => "title", reverse => 1)], ["post/3", "post/2", "post/1"]); @@ -22,10 +32,54 @@ is_deeply([pagespec_match_list("foo", "post/*", sort => "title", num => 2)], is_deeply([pagespec_match_list("foo", "post/*", sort => "title", num => 50)], ["post/1", "post/2", "post/3"]); is_deeply([pagespec_match_list("foo", "post/*", sort => "title", - limit => sub { $_[0] !~ /3/}) ], + filter => sub { $_[0] =~ /3/}) ], ["post/1", "post/2"]); my $r=eval { pagespec_match_list("foo", "beep") }; ok(eval { pagespec_match_list("foo", "beep") } == 0); ok(! $@, "does not fail with error when unable to match anything"); eval { pagespec_match_list("foo", "this is not a legal pagespec!") }; ok($@, "fails with error when pagespec bad"); + +# A pagespec that requires page metadata should add influences +# as an explicit dependency. In the case of a link, a links dependency. +foreach my $spec ("* and link(bar)", "* or link(bar)") { + pagespec_match_list("foo2", $spec, deptype => deptype("presence")); + ok($IkiWiki::depends{foo2}{$spec} & $IkiWiki::DEPEND_PRESENCE); + ok(! ($IkiWiki::depends{foo2}{$spec} & ($IkiWiki::DEPEND_CONTENT | $IkiWiki::DEPEND_LINKS))); + ok($IkiWiki::depends_simple{foo2}{foo2} == $IkiWiki::DEPEND_LINKS); + %IkiWiki::depends_simple=(); + %IkiWiki::depends=(); + pagespec_match_list("foo3", $spec, deptype => deptype("links")); + ok($IkiWiki::depends{foo3}{$spec} & $IkiWiki::DEPEND_LINKS); + ok(! ($IkiWiki::depends{foo3}{$spec} & ($IkiWiki::DEPEND_CONTENT | $IkiWiki::DEPEND_PRESENCE))); + ok($IkiWiki::depends_simple{foo3}{foo3} == $IkiWiki::DEPEND_LINKS); + %IkiWiki::depends_simple=(); + %IkiWiki::depends=(); +} + +# a pagespec with backlinks() will add as an influence the page with the links +foreach my $spec ("bar or (backlink(foo) and !*.png)", "backlink(foo)") { + pagespec_match_list("foo2", $spec, deptype => deptype("presence")); + ok($IkiWiki::depends{foo2}{$spec} & $IkiWiki::DEPEND_PRESENCE); + ok(! ($IkiWiki::depends{foo2}{$spec} & ($IkiWiki::DEPEND_CONTENT | $IkiWiki::DEPEND_LINKS))); + ok($IkiWiki::depends_simple{foo2}{foo} == $IkiWiki::DEPEND_LINKS); + %IkiWiki::depends_simple=(); + %IkiWiki::depends=(); + pagespec_match_list("foo2", $spec, deptype => deptype("links")); + ok($IkiWiki::depends{foo2}{$spec} & $IkiWiki::DEPEND_LINKS); + ok(! ($IkiWiki::depends{foo2}{$spec} & ($IkiWiki::DEPEND_PRESENCE | $IkiWiki::DEPEND_CONTENT))); + ok($IkiWiki::depends_simple{foo2}{foo} == $IkiWiki::DEPEND_LINKS); + %IkiWiki::depends_simple=(); + %IkiWiki::depends=(); + pagespec_match_list("foo2", $spec, deptype => deptype("presence", "links")); + ok($IkiWiki::depends{foo2}{$spec} & $IkiWiki::DEPEND_PRESENCE); + ok($IkiWiki::depends{foo2}{$spec} & $IkiWiki::DEPEND_LINKS); + ok(! ($IkiWiki::depends{foo2}{$spec} & $IkiWiki::DEPEND_CONTENT)); + ok($IkiWiki::depends_simple{foo2}{foo} == $IkiWiki::DEPEND_LINKS); + %IkiWiki::depends_simple=(); + %IkiWiki::depends=(); + pagespec_match_list("foo2", $spec); + ok($IkiWiki::depends{foo2}{$spec} & $IkiWiki::DEPEND_CONTENT); + ok(! ($IkiWiki::depends{foo2}{$spec} & ($IkiWiki::DEPEND_PRESENCE | $IkiWiki::DEPEND_LINKS))); + ok($IkiWiki::depends_simple{foo2}{foo} == $IkiWiki::DEPEND_LINKS); +} -- cgit v1.2.3 From 4ef0b2d77b6aa9db0a45e69c1db29998e4cc06fb Mon Sep 17 00:00:00 2001 From: Joey Hess Date: Fri, 9 Oct 2009 14:27:11 -0400 Subject: rework influence calculation Thought of a cleaner way to accumulate all influences in pagespec_match_list, using the pagespec_match result object as an accumulator. (This also accumulates all influences from failed matches, rather than just one failed match. I'm not sure if the old method was correct.) --- IkiWiki.pm | 36 ++++++++++-------------------------- 1 file changed, 10 insertions(+), 26 deletions(-) diff --git a/IkiWiki.pm b/IkiWiki.pm index 232d3e77b..c67a1e138 100644 --- a/IkiWiki.pm +++ b/IkiWiki.pm @@ -2032,41 +2032,25 @@ sub pagespec_match_list ($$;@) { my @matches; my $firstfail; my $count=0; + my $accum=IkiWiki::SuccessReason->new(); foreach my $p (@candidates) { my $r=$sub->($p, %params, location => $page); + error(sprintf(gettext("cannot match pages: %s"), $r)) + if $r->isa("IkiWiki::ErrorReason"); + $accum |= $r; if ($r) { - push @matches, [$p, $r]; + push @matches, $p; last if defined $num && ++$count == $num; } - elsif (! defined $firstfail) { - $firstfail=$r; - } - } - - 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)) - if $firstfail->isa("IkiWiki::ErrorReason"); + # Add simple dependencies for accumulated influences. + my %i=$accum->influences; + foreach my $i (keys %i) { + $depends_simple{$page}{lc $i} |= $i{$i}; } - return @ret; + return @matches; } sub pagespec_valid ($) { -- cgit v1.2.3 From ecbe5576f8b7152e96653669bc91eae021aaa91f Mon Sep 17 00:00:00 2001 From: Joey Hess Date: Fri, 9 Oct 2009 14:51:02 -0400 Subject: revert --- docwiki.setup | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docwiki.setup b/docwiki.setup index 41c07f024..52421e501 100644 --- a/docwiki.setup +++ b/docwiki.setup @@ -16,5 +16,5 @@ use IkiWiki::Setup::Standard { userdir => "users", usedirs => 0, prefix_directives => 1, - add_plugins => [qw{linkmap goodstuff version haiku polygen fortune}], + add_plugins => [qw{goodstuff version haiku polygen fortune}], } -- cgit v1.2.3 From 74409f940d24f51a08becb626e266c91d40d69bd Mon Sep 17 00:00:00 2001 From: Joey Hess Date: Fri, 9 Oct 2009 17:15:40 -0400 Subject: add_depends: optimise influence calculation I made match_* functions whose influences can vary depending on the page matched set a special "" influence to indicate this. Then add_depends can try just one page, and if static influences are found, stop there. --- IkiWiki.pm | 52 +++++++++++++++++++++++++------------------------- IkiWiki/Plugin/meta.pm | 6 +++--- doc/plugins/write.mdwn | 2 +- 3 files changed, 30 insertions(+), 30 deletions(-) diff --git a/IkiWiki.pm b/IkiWiki.pm index c67a1e138..cd93fe969 100644 --- a/IkiWiki.pm +++ b/IkiWiki.pm @@ -1780,19 +1780,17 @@ sub add_depends ($$;$) { return 1; } - # 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}; - # } - #} - print STDERR "warning: use of add_depends by ".caller()."; influences not tracked\n"; + # Add explicit dependencies for influences. + my $sub=pagespec_translate($pagespec); + return if $@; + foreach my $p (keys %pagesources) { + my $r=$sub->($p, location => $page); + my $i=$r->influences; + foreach my $k (keys %$i) { + $depends_simple{$page}{lc $k} |= $i->{$k}; + } + last if $r->influences_static; + } $depends{$page}{$pagespec} |= $deptype; return 1; @@ -2045,9 +2043,9 @@ sub pagespec_match_list ($$;@) { } # Add simple dependencies for accumulated influences. - my %i=$accum->influences; - foreach my $i (keys %i) { - $depends_simple{$page}{lc $i} |= $i{$i}; + my $i=$accum->influences; + foreach my $k (keys %$i) { + $depends_simple{$page}{lc $k} |= $i->{$k}; } return @matches; @@ -2099,12 +2097,14 @@ sub new { sub influences { my $this=shift; - if (! @_) { - return %{$this->[1]}; - } - else { - $this->[1]={@_}; - } + $this->[1]={@_} if @_; + my %i=%{$this->[1]}; + delete $i{""}; + return \%i; +} + +sub influences_static { + return ! $_[0][1]->{""}; } sub merge_influences { @@ -2173,19 +2173,19 @@ sub match_link ($$;@) { my $bestlink = IkiWiki::bestlink($from, $link); foreach my $p (@{$links}) { if (length $bestlink) { - return IkiWiki::SuccessReason->new("$page links to $link", $page => $IkiWiki::DEPEND_LINKS) + return IkiWiki::SuccessReason->new("$page links to $link", $page => $IkiWiki::DEPEND_LINKS, "" => 1) if $bestlink eq IkiWiki::bestlink($page, $p); } else { - return IkiWiki::SuccessReason->new("$page links to page $p matching $link", $page => $IkiWiki::DEPEND_LINKS) + return IkiWiki::SuccessReason->new("$page links to page $p matching $link", $page => $IkiWiki::DEPEND_LINKS, "" => 1) if match_glob($p, $link, %params); my ($p_rel)=$p=~/^\/?(.*)/; $link=~s/^\///; - return IkiWiki::SuccessReason->new("$page links to page $p_rel matching $link", $page => $IkiWiki::DEPEND_LINKS) + return IkiWiki::SuccessReason->new("$page links to page $p_rel matching $link", $page => $IkiWiki::DEPEND_LINKS, "" => 1) if match_glob($p_rel, $link, %params); } } - return IkiWiki::FailReason->new("$page does not link to $link"); + return IkiWiki::FailReason->new("$page does not link to $link", "" => 1); } sub match_backlink ($$;@) { diff --git a/IkiWiki/Plugin/meta.pm b/IkiWiki/Plugin/meta.pm index c675880b3..8dcd73a1a 100644 --- a/IkiWiki/Plugin/meta.pm +++ b/IkiWiki/Plugin/meta.pm @@ -291,14 +291,14 @@ sub match { if (defined $val) { if ($val=~/^$re$/i) { - return IkiWiki::SuccessReason->new("$re matches $field of $page", $page => $IkiWiki::DEPEND_CONTENT); + return IkiWiki::SuccessReason->new("$re matches $field of $page", $page => $IkiWiki::DEPEND_CONTENT, "" => 1); } else { - return IkiWiki::FailReason->new("$re does not match $field of $page"); + return IkiWiki::FailReason->new("$re does not match $field of $page", "" => 1); } } else { - return IkiWiki::FailReason->new("$page does not have a $field"); + return IkiWiki::FailReason->new("$page does not have a $field", "" => 1); } } diff --git a/doc/plugins/write.mdwn b/doc/plugins/write.mdwn index 2254d7025..c72418c3c 100644 --- a/doc/plugins/write.mdwn +++ b/doc/plugins/write.mdwn @@ -632,7 +632,7 @@ 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` and +is often significantly more efficient than calling `add_depends` and `pagespec_match` in a loop. You should use this anytime a plugin needs to match a set of pages and do something based on that list. -- cgit v1.2.3 From a169e7b6a81485a918992328f053d899e3614547 Mon Sep 17 00:00:00 2001 From: Joey Hess Date: Fri, 9 Oct 2009 20:30:22 -0400 Subject: update --- doc/todo/dependency_types.mdwn | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/doc/todo/dependency_types.mdwn b/doc/todo/dependency_types.mdwn index bf6a76d87..da9b5e6cf 100644 --- a/doc/todo/dependency_types.mdwn +++ b/doc/todo/dependency_types.mdwn @@ -566,9 +566,16 @@ SuccessReason(page, index) => right `HardFailReason() | SuccessReason(index)` => `SuccessReason(index)` => right +Ok so far, but: + "!bugs/* and link(patch)" => -`HardFailReason() | SuccessReason(bugs/foo)` => -`HardFailReason()` => right +`!SuccessReason() | SuccessReason(bugs/foo)` => +'FailReason() | SuccessReason(bugs/foo) +`FailReason(bugs/foo)` => wrong! + +This could be fixed by adding a HardSuccessReason that glob also returns. +Maybe just a field of the object that is set if it is "hard" is a better +approach though. #### Influence types -- cgit v1.2.3 From 6d6fff8d87ae304427e222d20e4e49e671e3b0f3 Mon Sep 17 00:00:00 2001 From: Joey Hess Date: Fri, 9 Oct 2009 21:12:14 -0400 Subject: added tests of SuccessReason/FailReason objects --- t/pagespec_match_result.t | 54 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) create mode 100755 t/pagespec_match_result.t diff --git a/t/pagespec_match_result.t b/t/pagespec_match_result.t new file mode 100755 index 000000000..2319d8733 --- /dev/null +++ b/t/pagespec_match_result.t @@ -0,0 +1,54 @@ +#!/usr/bin/perl +use warnings; +use strict; +use Test::More tests => 67; + +BEGIN { use_ok("IkiWiki"); } + +# Note that new objects have to be constructed freshly for each test, since +# object states are mutated as they are combined. +sub S { IkiWiki::SuccessReason->new("match") } +sub F { IkiWiki::FailReason->new("no match") } +sub E { IkiWiki::ErrorReason->new("error in matching") } + +ok(S() eq "match"); +ok(F() eq "no match"); +ok(E() eq "error in matching"); + +ok(S()); +ok(! F()); +ok(! E()); + +ok(!(! S())); +ok(!(!(! F))); +ok(!(!(! E))); + +ok(S() | F()); +ok(F() | S()); +ok(!(F() | E())); +ok(!(!S() | F() | E())); + +ok(S() & S() & S()); +ok(!(S() & E())); +ok(!(S() & F())); +ok(!(S() & F() & E())); +ok(S() & (F() | F() | S())); + +# influences are always merged, no matter the operation performed, +# as long as the two items are always both present +foreach my $op ('$s | $f', '$s & $f', '$s & $f & E()', '$s | E() | $f', + '! $s | ! $f', '!(!(!$s)) | $f') { + my $s=S(); + $s->influences(foo => 1, bar => 1); + is($s->influences->{foo}, 1); + is($s->influences->{bar}, 1); + my $f=F(); + $f->influences(bar => 2, baz => 1); + is($f->influences->{bar}, 2); + is($f->influences->{baz}, 1); + my $c = eval $op; + ok(ref $c); + is($c->influences->{foo}, 1, "foo ($op)"); + is($c->influences->{bar}, (1 | 2), "bar ($op)"); + is($c->influences->{baz}, 1, "baz ($op)"); +} -- cgit v1.2.3 From ba00fb319c6332977ac0cc78937151add5b91335 Mon Sep 17 00:00:00 2001 From: Joey Hess Date: Fri, 9 Oct 2009 21:23:39 -0400 Subject: update --- t/pagespec_match_result.t | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/t/pagespec_match_result.t b/t/pagespec_match_result.t index 2319d8733..d9c31d6f0 100755 --- a/t/pagespec_match_result.t +++ b/t/pagespec_match_result.t @@ -1,15 +1,15 @@ #!/usr/bin/perl use warnings; use strict; -use Test::More tests => 67; +use Test::More tests => 71; BEGIN { use_ok("IkiWiki"); } # Note that new objects have to be constructed freshly for each test, since # object states are mutated as they are combined. -sub S { IkiWiki::SuccessReason->new("match") } -sub F { IkiWiki::FailReason->new("no match") } -sub E { IkiWiki::ErrorReason->new("error in matching") } +sub S { IkiWiki::SuccessReason->new("match", @_) } +sub F { IkiWiki::FailReason->new("no match", @_) } +sub E { IkiWiki::ErrorReason->new("error in matching", @_) } ok(S() eq "match"); ok(F() eq "no match"); @@ -38,12 +38,10 @@ ok(S() & (F() | F() | S())); # as long as the two items are always both present foreach my $op ('$s | $f', '$s & $f', '$s & $f & E()', '$s | E() | $f', '! $s | ! $f', '!(!(!$s)) | $f') { - my $s=S(); - $s->influences(foo => 1, bar => 1); + my $s=S(foo => 1, bar => 1); is($s->influences->{foo}, 1); is($s->influences->{bar}, 1); - my $f=F(); - $f->influences(bar => 2, baz => 1); + my $f=F(bar => 2, baz => 1); is($f->influences->{bar}, 2); is($f->influences->{baz}, 1); my $c = eval $op; @@ -52,3 +50,10 @@ foreach my $op ('$s | $f', '$s & $f', '$s & $f & E()', '$s | E() | $f', is($c->influences->{bar}, (1 | 2), "bar ($op)"); is($c->influences->{baz}, 1, "baz ($op)"); } + +my $s=S(foo => 0, bar => 1); +$s->influences(baz => 1); +ok(! $s->influences->{foo}, "removed 0 influence"); +ok(! $s->influences->{bar}, "removed 1 influence"); +ok($s->influences->{baz}, "set influence"); +ok($s->influences_static); -- cgit v1.2.3 From 5dba91cdc88c01ac1d314f24b12eb2cda651e206 Mon Sep 17 00:00:00 2001 From: Joey Hess Date: Sun, 11 Oct 2009 13:51:23 -0400 Subject: typo --- doc/plugins/calendar.mdwn | 2 +- t/pagespec_match_result.t | 18 ++++++++++++++++++ 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/doc/plugins/calendar.mdwn b/doc/plugins/calendar.mdwn index d695762b7..8ade70004 100644 --- a/doc/plugins/calendar.mdwn +++ b/doc/plugins/calendar.mdwn @@ -6,7 +6,7 @@ The directive displays a calendar, similar to the typical calendars shown on some blogs. Since ikiwiki is a wiki compiler, to keep the calendar up-to-date, -wikis that include it need to be periodically refreshes, typically by cron +wikis that include it need to be periodically refreshed, typically by cron at midnight. Example crontab: 0 0 * * * ikiwiki -setup ~/ikiwiki.setup -refresh diff --git a/t/pagespec_match_result.t b/t/pagespec_match_result.t index d9c31d6f0..c2112bf14 100755 --- a/t/pagespec_match_result.t +++ b/t/pagespec_match_result.t @@ -57,3 +57,21 @@ ok(! $s->influences->{foo}, "removed 0 influence"); ok(! $s->influences->{bar}, "removed 1 influence"); ok($s->influences->{baz}, "set influence"); ok($s->influences_static); + +# influence blocking +my $r=F()->block & S(foo => 1); +ok(! $r->influences->{foo}, "failed blocker & influence -> does not pass"); +$r=F()->block | S(foo => 1); +ok($r->influences->{foo}, "failed blocker | influence -> does pass"); +$r=S(foo => 1) & F()->block; +ok(! $r->influences->{foo}, "influence & failed blocker -> does not pass"); +$r=S(foo => 1) | F()->block; +ok($r->influences->{foo}, "influence | failed blocker -> does pass"); +$r=S(foo => 1) & F()->block & S(foo => 2); +ok(! $r->influences->{foo}, "influence & failed blocker & influence -> does not pass"); +$r=S(foo => 1) | F()->block | S(foo => 2); +ok($r->influences->{foo}, "influence | failed blocker | influence -> does pass"); +$r=S()->block & S(foo => 1); +ok($r->influences->{foo}, "successful blocker -> does pass"); +$r=(! S()->block) & S(foo => 1); +ok(! $r->influences->{foo}, "! successful blocker -> failed blocker"); -- cgit v1.2.3 From 04d0a72c09528a4117b2ba641f5fdedbbe2a2171 Mon Sep 17 00:00:00 2001 From: Joey Hess Date: Sun, 11 Oct 2009 19:05:37 -0400 Subject: typo --- t/add_depends.t | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/t/add_depends.t b/t/add_depends.t index e3f0b6603..9b074818c 100755 --- a/t/add_depends.t +++ b/t/add_depends.t @@ -1,7 +1,7 @@ #!/usr/bin/perl use warnings; use strict; -use Test::More tests => 88; +use Test::More tests => 38; BEGIN { use_ok("IkiWiki"); } %config=IkiWiki::defaultconfig(); @@ -39,7 +39,7 @@ ok($IkiWiki::depends_simple{foo2}{"bar"} & $IkiWiki::DEPEND_LINKS); ok(! ($IkiWiki::depends_simple{foo2}{"bar"} & ($IkiWiki::DEPEND_PRESENCE | $IkiWiki::DEPEND_CONTENT))); # adding combined dep types -ok(add_depends("foo2", "baz", deptype("links". "presence"))); +ok(add_depends("foo2", "baz", deptype("links", "presence"))); ok($IkiWiki::depends_simple{foo2}{"baz"} & $IkiWiki::DEPEND_LINKS); ok($IkiWiki::depends_simple{foo2}{"baz"} & $IkiWiki::DEPEND_PRESENCE); ok(! ($IkiWiki::depends_simple{foo2}{"baz"} & $IkiWiki::DEPEND_CONTENT)); -- cgit v1.2.3 From 51d889951528a1de4f631435c2deccd1bd326ec5 Mon Sep 17 00:00:00 2001 From: Joey Hess Date: Sun, 11 Oct 2009 19:13:40 -0400 Subject: influences returns hash ref now --- t/pagespec_match.t | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/t/pagespec_match.t b/t/pagespec_match.t index ab3fcdd4b..d529106f7 100755 --- a/t/pagespec_match.t +++ b/t/pagespec_match.t @@ -93,19 +93,19 @@ $ret=pagespec_match("foo", "bar or foo"); ok($ret, "simple match"); is($ret, "foo matches foo", "stringified return"); -my %i=pagespec_match("foo", "link(bar)")->influences; -is(join(",", keys %i), 'foo', "link is influenced by the page with the link"); -%i=pagespec_match("bar", "backlink(foo)")->influences; -is(join(",", keys %i), 'foo', "backlink is influenced by the page with the link"); -%i=pagespec_match("bar", "backlink(foo)")->influences; -is(join(",", keys %i), 'foo', "backlink is influenced by the page with the link"); -%i=pagespec_match("bar", "created_before(foo)")->influences; -is(join(",", keys %i), 'foo', "created_before is influenced by the comparison page"); -%i=pagespec_match("bar", "created_after(foo)")->influences; -is(join(",", keys %i), 'foo', "created_after is influenced by the comparison page"); -%i=pagespec_match("foo", "link(baz) and created_after(bar)")->influences; -is(join(",", sort keys %i), 'bar,foo', "influences add up over AND"); -%i=pagespec_match("foo", "link(baz) and created_after(bar)")->influences; -is(join(",", sort keys %i), 'bar,foo', "influences add up over OR"); -%i=pagespec_match("foo", "!link(baz) and !created_after(bar)")->influences; -is(join(",", sort keys %i), 'bar,foo', "influences unaffected by negation"); +my $i=pagespec_match("foo", "link(bar)")->influences; +is(join(",", keys %$i), 'foo', "link is influenced by the page with the link"); +$i=pagespec_match("bar", "backlink(foo)")->influences; +is(join(",", keys %$i), 'foo', "backlink is influenced by the page with the link"); +$i=pagespec_match("bar", "backlink(foo)")->influences; +is(join(",", keys %$i), 'foo', "backlink is influenced by the page with the link"); +$i=pagespec_match("bar", "created_before(foo)")->influences; +is(join(",", keys %$i), 'foo', "created_before is influenced by the comparison page"); +$i=pagespec_match("bar", "created_after(foo)")->influences; +is(join(",", keys %$i), 'foo', "created_after is influenced by the comparison page"); +$i=pagespec_match("foo", "link(baz) and created_after(bar)")->influences; +is(join(",", sort keys %$i), 'bar,foo', "influences add up over AND"); +$i=pagespec_match("foo", "link(baz) and created_after(bar)")->influences; +is(join(",", sort keys %$i), 'bar,foo', "influences add up over OR"); +$i=pagespec_match("foo", "!link(baz) and !created_after(bar)")->influences; +is(join(",", sort keys %$i), 'bar,foo', "influences unaffected by negation"); -- cgit v1.2.3 From 71e266b939d72871f7efbc9c498dc9b472bdf9eb Mon Sep 17 00:00:00 2001 From: Joey Hess Date: Sun, 11 Oct 2009 20:15:54 -0400 Subject: avoid temporary variables and fix a bug in pagespec variable name --- IkiWiki/Plugin/calendar.pm | 118 ++++++++++++++++++--------------------------- 1 file changed, 48 insertions(+), 70 deletions(-) diff --git a/IkiWiki/Plugin/calendar.pm b/IkiWiki/Plugin/calendar.pm index c50d038df..fe7ee0361 100644 --- a/IkiWiki/Plugin/calendar.pm +++ b/IkiWiki/Plugin/calendar.pm @@ -65,16 +65,8 @@ sub month_days { sub format_month (@) { my %params=@_; - my $pagespec = $params{pages}; - my $year = $params{year}; - my $month = $params{month}; - my $pmonth = $params{pmonth}; - my $nmonth = $params{nmonth}; - my $pyear = $params{pyear}; - my $nyear = $params{nyear}; - my %linkcache; - foreach my $p (pagespec_match_list($params{page}, $params{pagespec}, + foreach my $p (pagespec_match_list($params{page}, $params{pages}, # add presence dependencies to update # month calendar when pages are added/removed deptype => deptype("presence"))) { @@ -94,19 +86,19 @@ sub format_month (@) { my $calendar="\n"; # When did this month start? - my @monthstart = localtime(timelocal(0,0,0,1,$month-1,$year-1900)); + my @monthstart = localtime(timelocal(0,0,0,1,$params{month}-1,$params{year}-1900)); my $future_dom = 0; my $today = 0; - if ($year == $now[5]+1900 && $month == $now[4]+1) { + if ($params{year} == $now[5]+1900 && $params{month} == $now[4]+1) { $future_dom = $now[3]+1; $today = $now[3]; } # Find out month names for this, next, and previous months my $monthname=POSIX::strftime("%B", @monthstart); - my $pmonthname=POSIX::strftime("%B", localtime(timelocal(0,0,0,1,$pmonth-1,$pyear-1900))); - my $nmonthname=POSIX::strftime("%B", localtime(timelocal(0,0,0,1,$nmonth-1,$nyear-1900))); + my $pmonthname=POSIX::strftime("%B", localtime(timelocal(0,0,0,1,$params{pmonth}-1,$params{pyear}-1900))); + my $nmonthname=POSIX::strftime("%B", localtime(timelocal(0,0,0,1,$params{nmonth}-1,$params{nyear}-1900))); my $archivebase = 'archives'; $archivebase = $config{archivebase} if defined $config{archivebase}; @@ -114,26 +106,26 @@ sub format_month (@) { # Calculate URL's for monthly archives. my ($url, $purl, $nurl)=("$monthname",'',''); - if (exists $pagesources{"$archivebase/$year/$month"}) { + if (exists $pagesources{"$archivebase/$params{year}/$params{month}"}) { $url = htmllink($params{page}, $params{destpage}, - "$archivebase/$year/".sprintf("%02d", $month), + "$archivebase/$params{year}/".sprintf("%02d", $params{month}), linktext => " $monthname "); } - add_depends($params{page}, "$archivebase/$year/".sprintf("%02d", $month), + add_depends($params{page}, "$archivebase/$params{year}/".sprintf("%02d", $params{month}), deptype("presence")); - if (exists $pagesources{"$archivebase/$pyear/$pmonth"}) { + if (exists $pagesources{"$archivebase/$params{pyear}/$params{pmonth}"}) { $purl = htmllink($params{page}, $params{destpage}, - "$archivebase/$pyear/" . sprintf("%02d", $pmonth), + "$archivebase/$params{pyear}/" . sprintf("%02d", $params{pmonth}), linktext => " $pmonthname "); } - add_depends($params{page}, "$archivebase/$pyear/".sprintf("%02d", $pmonth), + add_depends($params{page}, "$archivebase/$params{pyear}/".sprintf("%02d", $params{pmonth}), deptype("presence")); - if (exists $pagesources{"$archivebase/$nyear/$nmonth"}) { + if (exists $pagesources{"$archivebase/$params{nyear}/$params{nmonth}"}) { $nurl = htmllink($params{page}, $params{destpage}, - "$archivebase/$nyear/" . sprintf("%02d", $nmonth), + "$archivebase/$params{nyear}/" . sprintf("%02d", $params{nmonth}), linktext => " $nmonthname "); } - add_depends($params{page}, "$archivebase/$nyear/".sprintf("%02d", $nmonth), + add_depends($params{page}, "$archivebase/$params{nyear}/".sprintf("%02d", $params{nmonth}), deptype("presence")); # Start producing the month calendar @@ -155,7 +147,7 @@ EOF my %downame; my %dowabbr; for my $dow ($week_start_day..$week_start_day+6) { - my @day=localtime(timelocal(0,0,0,$start_day++,$month-1,$year-1900)); + my @day=localtime(timelocal(0,0,0,$start_day++,$params{month}-1,$params{year}-1900)); my $downame = POSIX::strftime("%A", @day); my $dowabbr = POSIX::strftime("%a", @day); $downame{$dow % 7}=$downame; @@ -176,7 +168,7 @@ EOF # At this point, either the first is a week_start_day, in which case # nothing has been printed, or else we are in the middle of a row. - for (my $day = 1; $day <= month_days(year => $year, month => $month); + for (my $day = 1; $day <= month_days(year => $params{year}, month => $params{month}); $day++, $wday++, $wday %= 7) { # At tihs point, on a week_start_day, we close out a row, # and start a new one -- unless it is week_start_day on the @@ -187,8 +179,8 @@ EOF } my $tag; - my $mtag = sprintf("%02d", $month); - if (defined $pagesources{"$archivebase/$year/$mtag/$day"}) { + my $mtag = sprintf("%02d", $params{month}); + if (defined $pagesources{"$archivebase/$params{year}/$mtag/$day"}) { if ($day == $today) { $tag='month-calendar-day-this-day'; } @@ -197,9 +189,9 @@ EOF } $calendar.=qq{\t\t}; $calendar.=htmllink($params{page}, $params{destpage}, - pagename($linkcache{"$year/$mtag/$day"}), + pagename($linkcache{"$params{year}/$mtag/$day"}), "linktext" => "$day"); - push @list, pagename($linkcache{"$year/$mtag/$day"}); + push @list, pagename($linkcache{"$params{year}/$mtag/$day"}); $calendar.=qq{\n}; } else { @@ -231,43 +223,35 @@ EOF sub format_year (@) { my %params=@_; - my $pagespec = $params{pages}; - my $year = $params{year}; - my $month = $params{month}; - my $pmonth = $params{pmonth}; - my $nmonth = $params{nmonth}; - my $pyear = $params{pyear}; - my $nyear = $params{nyear}; - my $calendar="\n"; my $future_month = 0; - $future_month = $now[4]+1 if ($year == $now[5]+1900); + $future_month = $now[4]+1 if ($params{year} == $now[5]+1900); my $archivebase = 'archives'; $archivebase = $config{archivebase} if defined $config{archivebase}; $archivebase = $params{archivebase} if defined $params{archivebase}; # calculate URL's for previous and next years - my ($url, $purl, $nurl)=("$year",'',''); - if (exists $pagesources{"$archivebase/$year"}) { + my ($url, $purl, $nurl)=("$params{year}",'',''); + if (exists $pagesources{"$archivebase/$params{year}"}) { $url = htmllink($params{page}, $params{destpage}, - "$archivebase/$year", - linktext => "$year"); + "$archivebase/$params{year}", + linktext => "$params{year}"); } - add_depends($params{page}, "$archivebase/$year", deptype("presence")); - if (exists $pagesources{"$archivebase/$pyear"}) { + add_depends($params{page}, "$archivebase/$params{year}", deptype("presence")); + if (exists $pagesources{"$archivebase/$params{pyear}"}) { $purl = htmllink($params{page}, $params{destpage}, - "$archivebase/$pyear", + "$archivebase/$params{pyear}", linktext => "\←"); } - add_depends($params{page}, "$archivebase/$pyear", deptype("presence")); - if (exists $pagesources{"$archivebase/$nyear"}) { + add_depends($params{page}, "$archivebase/$params{pyear}", deptype("presence")); + if (exists $pagesources{"$archivebase/$params{nyear}"}) { $nurl = htmllink($params{page}, $params{destpage}, - "$archivebase/$nyear", + "$archivebase/$params{nyear}", linktext => "\→"); } - add_depends($params{page}, "$archivebase/$nyear", deptype("presence")); + add_depends($params{page}, "$archivebase/$params{nyear}", deptype("presence")); # Start producing the year calendar $calendar=< EOF - for ($month = 1; $month <= 12; $month++) { - my @day=localtime(timelocal(0,0,0,15,$month-1,$year-1900)); + for (my $month = 1; $month <= 12; $month++) { + my @day=localtime(timelocal(0,0,0,15,$month-1,$params{year}-1900)); my $murl; my $monthname = POSIX::strftime("%B", @day); my $monthabbr = POSIX::strftime("%b", @day); @@ -291,14 +275,14 @@ EOF my $tag; my $mtag=sprintf("%02d", $month); if ($month == $params{month}) { - if ($pagesources{"$archivebase/$year/$mtag"}) { + if ($pagesources{"$archivebase/$params{year}/$mtag"}) { $tag = 'this_month_link'; } else { $tag = 'this_month_nolink'; } } - elsif ($pagesources{"$archivebase/$year/$mtag"}) { + elsif ($pagesources{"$archivebase/$params{year}/$mtag"}) { $tag = 'month_link'; } elsif ($future_month && $month >= $future_month) { @@ -308,9 +292,9 @@ EOF $tag = 'month_nolink'; } - if ($pagesources{"$archivebase/$year/$mtag"}) { + if ($pagesources{"$archivebase/$params{year}/$mtag"}) { $murl = htmllink($params{page}, $params{destpage}, - "$archivebase/$year/$mtag", + "$archivebase/$params{year}/$mtag", linktext => "$monthabbr"); $calendar.=qq{\t}; $calendar.=$murl; @@ -319,7 +303,7 @@ EOF else { $calendar.=qq{\t$monthabbr\n}; } - add_depends($params{page}, "$archivebase/$year/$mtag", + add_depends($params{page}, "$archivebase/$params{year}/$mtag", deptype("presence")); $calendar.=qq{\t\n} if ($month % $params{months_per_row} == 0); @@ -356,28 +340,22 @@ sub preprocess (@) { } # Calculate month names for next month, and previous months - my $pmonth = $params{month} - 1; - my $nmonth = $params{month} + 1; - my $pyear = $params{year} - 1; - my $nyear = $params{year} + 1; + $params{pmonth} = $params{month} - 1; + $params{nmonth} = $params{month} + 1; + $params{pyear} = $params{year} - 1; + $params{nyear} = $params{year} + 1; # Adjust for January and December if ($params{month} == 1) { - $pmonth = 12; - $pyear--; + $params{pmonth} = 12; + $params{pyear}--; } if ($params{month} == 12) { - $nmonth = 1; - $nyear++; + $params{nmonth} = 1; + $params{nyear}++; } - $params{pmonth}=$pmonth; - $params{nmonth}=$nmonth; - $params{pyear} =$pyear; - $params{nyear} =$nyear; - - my $calendar="\n"; - + my $calendar=""; if ($params{type} =~ /month/i) { $calendar=format_month(%params); } -- cgit v1.2.3 From dd80be66ee7d9a28e788efcc1b3eb62bbe8611dd Mon Sep 17 00:00:00 2001 From: Joey Hess Date: Sun, 11 Oct 2009 21:06:10 -0400 Subject: calendar: Fix midnight rebuild trigger of calendars with explicit month/year. It was just broken for calendars with an explicit month or year, not triggering at all. Now it will update those at appropriate times. --- IkiWiki/Plugin/calendar.pm | 42 +++++++++++++++++++++++++++++++++--------- debian/changelog | 2 ++ 2 files changed, 35 insertions(+), 9 deletions(-) diff --git a/IkiWiki/Plugin/calendar.pm b/IkiWiki/Plugin/calendar.pm index fe7ee0361..9cbfd769d 100644 --- a/IkiWiki/Plugin/calendar.pm +++ b/IkiWiki/Plugin/calendar.pm @@ -318,24 +318,48 @@ EOF sub preprocess (@) { my %params=@_; + + my $thisyear=1900 + $now[5]; + my $thismonth=1 + $now[4]; + $params{pages} = "*" unless defined $params{pages}; $params{type} = "month" unless defined $params{type}; - $params{month} = sprintf("%02d", $params{month}) if defined $params{month}; $params{week_start_day} = 0 unless defined $params{week_start_day}; $params{months_per_row} = 3 unless defined $params{months_per_row}; - - if (! defined $params{year} || ! defined $params{month}) { - # Record that the calendar next changes at midnight. + $params{year} = $thisyear unless defined $params{year}; + $params{month} = $thismonth unless defined $params{month}; + + $params{month} = sprintf("%02d", $params{month}); + + if ($params{type} eq 'month' && $params{year} == $thisyear + && $params{month} == $thismonth) { + # calendar for current month, updates next midnight $pagestate{$params{destpage}}{calendar}{nextchange}=($time + (60 - $now[0]) # seconds + (59 - $now[1]) * 60 # minutes + (23 - $now[2]) * 60 * 60 # hours ); - - $params{year} = 1900 + $now[5] unless defined $params{year}; - $params{month} = 1 + $now[4] unless defined $params{month}; + } + elsif ($params{type} eq 'month' && + (($params{year} == $thisyear && $params{month} > $thismonth) || + $params{year} > $thisyear)) { + # calendar for upcoming month, updates 1st of that month + $pagestate{$params{destpage}}{calendar}{nextchange}= + timelocal(0, 0, 0, 1, $params{month}-1, $params{year}); + } + elsif ($params{type} eq 'year' && $params{year} == $thisyear) { + # calendar for current year, updates 1st of next month + $pagestate{$params{destpage}}{calendar}{nextchange}= + timelocal(0, 0, 0, 1, $thismonth+1-1, $params{year}); + } + elsif ($params{type} eq 'year' && $params{year} > $thisyear) { + # calendar for upcoming year, updates 1st of that year + $pagestate{$params{destpage}}{calendar}{nextchange}= + timelocal(0, 0, 0, 1, 1-1, $params{year}); } else { + # calendar for past month or year, does not need + # to update any more delete $pagestate{$params{destpage}}{calendar}; } @@ -356,10 +380,10 @@ sub preprocess (@) { } my $calendar=""; - if ($params{type} =~ /month/i) { + if ($params{type} eq 'month') { $calendar=format_month(%params); } - elsif ($params{type} =~ /year/i) { + elsif ($params{type} eq 'year') { $calendar=format_year(%params); } diff --git a/debian/changelog b/debian/changelog index 0e288dd08..c64758a77 100644 --- a/debian/changelog +++ b/debian/changelog @@ -28,6 +28,8 @@ ikiwiki (3.2009XXXX) UNRELEASED; urgency=low * Transitive dependencies are now correctly supported. * ikiwiki-calendar: New command automates creation of archive pages using the calendar plugin. + * calendar: Fix midnight rebuild trigger of calendars with explicit + month/year. -- Joey Hess Fri, 09 Oct 2009 19:53:50 -0400 -- cgit v1.2.3 From f3342773d3a6c9da11c248c4cc385dca284add06 Mon Sep 17 00:00:00 2001 From: Joey Hess Date: Sun, 11 Oct 2009 21:42:59 -0400 Subject: calendar: Fix bug in next/previous year/month links, which sometimes linked to an archive page from the wrong year. --- IkiWiki/Plugin/calendar.pm | 63 ++++++++++++++++++++++++---------------------- debian/changelog | 2 ++ 2 files changed, 35 insertions(+), 30 deletions(-) diff --git a/IkiWiki/Plugin/calendar.pm b/IkiWiki/Plugin/calendar.pm index 9cbfd769d..5b4bfac89 100644 --- a/IkiWiki/Plugin/calendar.pm +++ b/IkiWiki/Plugin/calendar.pm @@ -81,6 +81,21 @@ sub format_month (@) { # Only one posting per day is being linked to. $linkcache{"$year/$mtag/$mday"} = "$src"; } + + my $pmonth = $params{month} - 1; + my $nmonth = $params{month} + 1; + my $pyear = $params{year}; + my $nyear = $params{year}; + + # Adjust for January and December + if ($params{month} == 1) { + $pmonth = 12; + $pyear--; + } + if ($params{month} == 12) { + $nmonth = 1; + $nyear++; + } my @list; my $calendar="\n"; @@ -97,8 +112,8 @@ sub format_month (@) { # Find out month names for this, next, and previous months my $monthname=POSIX::strftime("%B", @monthstart); - my $pmonthname=POSIX::strftime("%B", localtime(timelocal(0,0,0,1,$params{pmonth}-1,$params{pyear}-1900))); - my $nmonthname=POSIX::strftime("%B", localtime(timelocal(0,0,0,1,$params{nmonth}-1,$params{nyear}-1900))); + my $pmonthname=POSIX::strftime("%B", localtime(timelocal(0,0,0,1,$pmonth-1,$pyear-1900))); + my $nmonthname=POSIX::strftime("%B", localtime(timelocal(0,0,0,1,$nmonth-1,$nyear-1900))); my $archivebase = 'archives'; $archivebase = $config{archivebase} if defined $config{archivebase}; @@ -113,19 +128,19 @@ sub format_month (@) { } add_depends($params{page}, "$archivebase/$params{year}/".sprintf("%02d", $params{month}), deptype("presence")); - if (exists $pagesources{"$archivebase/$params{pyear}/$params{pmonth}"}) { + if (exists $pagesources{"$archivebase/$pyear/$pmonth"}) { $purl = htmllink($params{page}, $params{destpage}, - "$archivebase/$params{pyear}/" . sprintf("%02d", $params{pmonth}), + "$archivebase/$pyear/" . sprintf("%02d", $pmonth), linktext => " $pmonthname "); } - add_depends($params{page}, "$archivebase/$params{pyear}/".sprintf("%02d", $params{pmonth}), + add_depends($params{page}, "$archivebase/$pyear/".sprintf("%02d", $pmonth), deptype("presence")); - if (exists $pagesources{"$archivebase/$params{nyear}/$params{nmonth}"}) { + if (exists $pagesources{"$archivebase/$nyear/$nmonth"}) { $nurl = htmllink($params{page}, $params{destpage}, - "$archivebase/$params{nyear}/" . sprintf("%02d", $params{nmonth}), + "$archivebase/$nyear/" . sprintf("%02d", $nmonth), linktext => " $nmonthname "); } - add_depends($params{page}, "$archivebase/$params{nyear}/".sprintf("%02d", $params{nmonth}), + add_depends($params{page}, "$archivebase/$nyear/".sprintf("%02d", $nmonth), deptype("presence")); # Start producing the month calendar @@ -222,8 +237,11 @@ EOF sub format_year (@) { my %params=@_; - + my $calendar="\n"; + + my $pyear = $params{year} - 1; + my $nyear = $params{year} + 1; my $future_month = 0; $future_month = $now[4]+1 if ($params{year} == $now[5]+1900); @@ -240,18 +258,18 @@ sub format_year (@) { linktext => "$params{year}"); } add_depends($params{page}, "$archivebase/$params{year}", deptype("presence")); - if (exists $pagesources{"$archivebase/$params{pyear}"}) { + if (exists $pagesources{"$archivebase/$pyear"}) { $purl = htmllink($params{page}, $params{destpage}, - "$archivebase/$params{pyear}", + "$archivebase/$pyear", linktext => "\←"); } - add_depends($params{page}, "$archivebase/$params{pyear}", deptype("presence")); - if (exists $pagesources{"$archivebase/$params{nyear}"}) { + add_depends($params{page}, "$archivebase/$pyear", deptype("presence")); + if (exists $pagesources{"$archivebase/$nyear"}) { $nurl = htmllink($params{page}, $params{destpage}, - "$archivebase/$params{nyear}", + "$archivebase/$nyear", linktext => "\→"); } - add_depends($params{page}, "$archivebase/$params{nyear}", deptype("presence")); + add_depends($params{page}, "$archivebase/$nyear", deptype("presence")); # Start producing the year calendar $calendar=< Fri, 09 Oct 2009 19:53:50 -0400 -- cgit v1.2.3 From 8a37be35acb2c2c37d272489d2f2678e47c61834 Mon Sep 17 00:00:00 2001 From: Joey Hess Date: Sun, 11 Oct 2009 21:43:16 -0400 Subject: fix day links I broke this recently. --- IkiWiki/Plugin/calendar.pm | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/IkiWiki/Plugin/calendar.pm b/IkiWiki/Plugin/calendar.pm index 5b4bfac89..0266612ae 100644 --- a/IkiWiki/Plugin/calendar.pm +++ b/IkiWiki/Plugin/calendar.pm @@ -71,7 +71,6 @@ sub format_month (@) { # month calendar when pages are added/removed deptype => deptype("presence"))) { my $mtime = $IkiWiki::pagectime{$p}; - my $src = $pagesources{$p}; my @date = localtime($mtime); my $mday = $date[3]; my $month = $date[4] + 1; @@ -79,7 +78,7 @@ sub format_month (@) { my $mtag = sprintf("%02d", $month); # Only one posting per day is being linked to. - $linkcache{"$year/$mtag/$mday"} = "$src"; + $linkcache{"$year/$mtag/$mday"} = $p; } my $pmonth = $params{month} - 1; @@ -97,7 +96,6 @@ sub format_month (@) { $nyear++; } - my @list; my $calendar="\n"; # When did this month start? @@ -195,7 +193,7 @@ EOF my $tag; my $mtag = sprintf("%02d", $params{month}); - if (defined $pagesources{"$archivebase/$params{year}/$mtag/$day"}) { + if (defined $linkcache{"$params{year}/$mtag/$day"}) { if ($day == $today) { $tag='month-calendar-day-this-day'; } @@ -204,9 +202,8 @@ EOF } $calendar.=qq{\t\t}; $calendar.=htmllink($params{page}, $params{destpage}, - pagename($linkcache{"$params{year}/$mtag/$day"}), + $linkcache{"$params{year}/$mtag/$day"}, "linktext" => "$day"); - push @list, pagename($linkcache{"$params{year}/$mtag/$day"}); $calendar.=qq{\n}; } else { -- cgit v1.2.3 From 23a21850faf1cbb4bd8547b11563c5806617cf7e Mon Sep 17 00:00:00 2001 From: Joey Hess Date: Sun, 11 Oct 2009 21:52:50 -0400 Subject: fix next/prev month padding bug --- IkiWiki/Plugin/calendar.pm | 21 ++++++++++++--------- debian/changelog | 2 +- 2 files changed, 13 insertions(+), 10 deletions(-) diff --git a/IkiWiki/Plugin/calendar.pm b/IkiWiki/Plugin/calendar.pm index 0266612ae..cf133e8dc 100644 --- a/IkiWiki/Plugin/calendar.pm +++ b/IkiWiki/Plugin/calendar.pm @@ -96,6 +96,10 @@ sub format_month (@) { $nyear++; } + # Add padding. + $pmonth=sprintf("%02d", $pmonth); + $nmonth=sprintf("%02d", $nmonth); + my $calendar="\n"; # When did this month start? @@ -121,24 +125,24 @@ sub format_month (@) { my ($url, $purl, $nurl)=("$monthname",'',''); if (exists $pagesources{"$archivebase/$params{year}/$params{month}"}) { $url = htmllink($params{page}, $params{destpage}, - "$archivebase/$params{year}/".sprintf("%02d", $params{month}), + "$archivebase/$params{year}/".$params{month}, linktext => " $monthname "); } - add_depends($params{page}, "$archivebase/$params{year}/".sprintf("%02d", $params{month}), + add_depends($params{page}, "$archivebase/$params{year}/$params{month}", deptype("presence")); if (exists $pagesources{"$archivebase/$pyear/$pmonth"}) { $purl = htmllink($params{page}, $params{destpage}, - "$archivebase/$pyear/" . sprintf("%02d", $pmonth), + "$archivebase/$pyear/$pmonth", linktext => " $pmonthname "); } - add_depends($params{page}, "$archivebase/$pyear/".sprintf("%02d", $pmonth), + add_depends($params{page}, "$archivebase/$pyear/$pmonth", deptype("presence")); if (exists $pagesources{"$archivebase/$nyear/$nmonth"}) { $nurl = htmllink($params{page}, $params{destpage}, - "$archivebase/$nyear/" . sprintf("%02d", $nmonth), + "$archivebase/$nyear/$nmonth", linktext => " $nmonthname "); } - add_depends($params{page}, "$archivebase/$nyear/".sprintf("%02d", $nmonth), + add_depends($params{page}, "$archivebase/$nyear/$nmonth", deptype("presence")); # Start producing the month calendar @@ -192,8 +196,7 @@ EOF } my $tag; - my $mtag = sprintf("%02d", $params{month}); - if (defined $linkcache{"$params{year}/$mtag/$day"}) { + if (defined $linkcache{"$params{year}/$params{month}/$day"}) { if ($day == $today) { $tag='month-calendar-day-this-day'; } @@ -202,7 +205,7 @@ EOF } $calendar.=qq{\t\t}; $calendar.=htmllink($params{page}, $params{destpage}, - $linkcache{"$params{year}/$mtag/$day"}, + $linkcache{"$params{year}/$params{month}/$day"}, "linktext" => "$day"); $calendar.=qq{\n}; } diff --git a/debian/changelog b/debian/changelog index 8881c48aa..5c47b2524 100644 --- a/debian/changelog +++ b/debian/changelog @@ -31,7 +31,7 @@ ikiwiki (3.2009XXXX) UNRELEASED; urgency=low * calendar: Fix midnight rebuild trigger of calendars with explicit month/year. * calendar: Fix bug in next/previous year/month links, which sometimes - linked to an archive page from the wrong year. + linked to an archive page from the wrong year, or were missing. -- Joey Hess Fri, 09 Oct 2009 19:53:50 -0400 -- cgit v1.2.3 From cf74cf7a37a1fa4e02dffc6f3ac580626d183433 Mon Sep 17 00:00:00 2001 From: Joey Hess Date: Sun, 11 Oct 2009 21:55:06 -0400 Subject: calendar: use left and right arrows for next/prev months This is consistent with the year display, and I think it is less visually confusing than using the full month names. --- IkiWiki/Plugin/calendar.pm | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/IkiWiki/Plugin/calendar.pm b/IkiWiki/Plugin/calendar.pm index cf133e8dc..dcf2b6d64 100644 --- a/IkiWiki/Plugin/calendar.pm +++ b/IkiWiki/Plugin/calendar.pm @@ -133,14 +133,14 @@ sub format_month (@) { if (exists $pagesources{"$archivebase/$pyear/$pmonth"}) { $purl = htmllink($params{page}, $params{destpage}, "$archivebase/$pyear/$pmonth", - linktext => " $pmonthname "); + linktext => " \&larr "); } add_depends($params{page}, "$archivebase/$pyear/$pmonth", deptype("presence")); if (exists $pagesources{"$archivebase/$nyear/$nmonth"}) { $nurl = htmllink($params{page}, $params{destpage}, "$archivebase/$nyear/$nmonth", - linktext => " $nmonthname "); + linktext => " \&rarr "); } add_depends($params{page}, "$archivebase/$nyear/$nmonth", deptype("presence")); -- cgit v1.2.3 From e4c765c64fc31ab13c911b716e80b07b4d1a0037 Mon Sep 17 00:00:00 2001 From: Joey Hess Date: Sun, 11 Oct 2009 22:11:11 -0400 Subject: calendar: avoid inline images in links --- IkiWiki/Plugin/calendar.pm | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/IkiWiki/Plugin/calendar.pm b/IkiWiki/Plugin/calendar.pm index dcf2b6d64..e3c5e2f2d 100644 --- a/IkiWiki/Plugin/calendar.pm +++ b/IkiWiki/Plugin/calendar.pm @@ -126,6 +126,7 @@ sub format_month (@) { if (exists $pagesources{"$archivebase/$params{year}/$params{month}"}) { $url = htmllink($params{page}, $params{destpage}, "$archivebase/$params{year}/".$params{month}, + noimageinline => 1, linktext => " $monthname "); } add_depends($params{page}, "$archivebase/$params{year}/$params{month}", @@ -133,6 +134,7 @@ sub format_month (@) { if (exists $pagesources{"$archivebase/$pyear/$pmonth"}) { $purl = htmllink($params{page}, $params{destpage}, "$archivebase/$pyear/$pmonth", + noimageinline => 1, linktext => " \&larr "); } add_depends($params{page}, "$archivebase/$pyear/$pmonth", @@ -140,6 +142,7 @@ sub format_month (@) { if (exists $pagesources{"$archivebase/$nyear/$nmonth"}) { $nurl = htmllink($params{page}, $params{destpage}, "$archivebase/$nyear/$nmonth", + noimageinline => 1, linktext => " \&rarr "); } add_depends($params{page}, "$archivebase/$nyear/$nmonth", @@ -205,8 +208,9 @@ EOF } $calendar.=qq{\t\t}; $calendar.=htmllink($params{page}, $params{destpage}, - $linkcache{"$params{year}/$params{month}/$day"}, - "linktext" => "$day"); + $linkcache{"$params{year}/$params{month}/$day"}, + noimageinline => 1, + "linktext" => "$day"); $calendar.=qq{\n}; } else { @@ -255,18 +259,21 @@ sub format_year (@) { if (exists $pagesources{"$archivebase/$params{year}"}) { $url = htmllink($params{page}, $params{destpage}, "$archivebase/$params{year}", + noimageinline => 1, linktext => "$params{year}"); } add_depends($params{page}, "$archivebase/$params{year}", deptype("presence")); if (exists $pagesources{"$archivebase/$pyear"}) { $purl = htmllink($params{page}, $params{destpage}, "$archivebase/$pyear", + noimageinline => 1, linktext => "\←"); } add_depends($params{page}, "$archivebase/$pyear", deptype("presence")); if (exists $pagesources{"$archivebase/$nyear"}) { $nurl = htmllink($params{page}, $params{destpage}, "$archivebase/$nyear", + noimageinline => 1, linktext => "\→"); } add_depends($params{page}, "$archivebase/$nyear", deptype("presence")); @@ -313,6 +320,7 @@ EOF if ($pagesources{"$archivebase/$params{year}/$mtag"}) { $murl = htmllink($params{page}, $params{destpage}, "$archivebase/$params{year}/$mtag", + noimageinline => 1, linktext => "$monthabbr"); $calendar.=qq{\t}; $calendar.=$murl; -- cgit v1.2.3 From bf577d34c79ebe48efdf06ed826f9109e196cc6d Mon Sep 17 00:00:00 2001 From: Joey Hess Date: Sun, 11 Oct 2009 23:07:31 -0400 Subject: can't use --reverse with git log --follow Meh, git. --- IkiWiki/Plugin/git.pm | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/IkiWiki/Plugin/git.pm b/IkiWiki/Plugin/git.pm index e10283f59..9ecda4ffb 100644 --- a/IkiWiki/Plugin/git.pm +++ b/IkiWiki/Plugin/git.pm @@ -613,11 +613,14 @@ sub rcs_getctime ($) { # Remove srcdir prefix $file =~ s/^\Q$config{srcdir}\E\/?//; - my @raw_lines = run_or_die('git', 'log', '--reverse', '--follow', + my @raw_lines = run_or_die('git', 'log', '--follow', '--pretty=raw', '--raw', '--abbrev=40', '--always', '-c', '-r', '--', $file); - my $first = parse_diff_tree("", \@raw_lines); - my $ctime = $first->{'author_epoch'}; + my @ci; + while (my $parsed = parse_diff_tree("", \@raw_lines)) { + push @ci, $parsed; + } + my $ctime = $ci[$#ci]->{'author_epoch'}; debug("ctime for '$file': ". localtime($ctime)); return $ctime; -- cgit v1.2.3 From 1c6794f46a729eea8c7e7d49fcf7c6a54dae2ba9 Mon Sep 17 00:00:00 2001 From: Joey Hess Date: Sun, 11 Oct 2009 23:44:50 -0400 Subject: allow spans --- doc/ikiwiki-calendar.mdwn | 6 +++--- ikiwiki-calendar | 5 +++-- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/doc/ikiwiki-calendar.mdwn b/doc/ikiwiki-calendar.mdwn index e2cc612f3..3f5c6a29e 100644 --- a/doc/ikiwiki-calendar.mdwn +++ b/doc/ikiwiki-calendar.mdwn @@ -4,7 +4,7 @@ ikiwiki-calendar - create calendar archive pages # SYNOPSIS -ikiwiki-calendar [-f] your.setup [pagespec] [year] +ikiwiki-calendar [-f] your.setup [pagespec] [startyear [endyear]] # DESCRIPTION @@ -22,8 +22,8 @@ default is all pages. To limit it to only posts in a blog, use something like "posts/* and !*/Discussion". It defaults to creating calendar pages for the current -year, as well as the previous year, and the next year. -If you specify a year, it will create pages for that year. +year. If you specify a year, it will create pages for that year. +Specify a second year to create pages for a span of years. Existing pages will not be overwritten by this command by default. Use the `-f` switch to force it to overwrite any existing pages. diff --git a/ikiwiki-calendar b/ikiwiki-calendar index 074f0d6fd..a9548d6ec 100755 --- a/ikiwiki-calendar +++ b/ikiwiki-calendar @@ -15,7 +15,8 @@ GetOptions( ) || usage(); my $setup=shift || usage(); my $pagespec=shift || "*"; -my $year=shift || 1900+(localtime(time))[5]; +my $startyear=shift || 1900+(localtime(time))[5]; +my $endyear=shift || $startyear; %config=IkiWiki::defaultconfig(); IkiWiki::Setup::load($setup); @@ -43,7 +44,7 @@ sub writearchive ($$;$) { } } -foreach my $y ($year-1, $year, $year+1) { +foreach my $y ($startyear..$endyear) { writearchive("calendaryear.tmpl", $y); foreach my $m (qw{01 02 03 04 05 06 07 08 09 10 11 12}) { writearchive("calendarmonth.tmpl", $y, $m); -- cgit v1.2.3 From 139085b3f294f3a8e3fd1663aa232a9e901ca3e1 Mon Sep 17 00:00:00 2001 From: Joey Hess Date: Sun, 11 Oct 2009 23:53:21 -0400 Subject: add some TODO tests for influence blocking --- t/pagespec_match_list.t | 31 ++++++++++++++++++++++++++++++- t/pagespec_match_result.t | 18 ------------------ 2 files changed, 30 insertions(+), 19 deletions(-) diff --git a/t/pagespec_match_list.t b/t/pagespec_match_list.t index 301197cc1..51145a973 100755 --- a/t/pagespec_match_list.t +++ b/t/pagespec_match_list.t @@ -1,7 +1,7 @@ #!/usr/bin/perl use warnings; use strict; -use Test::More tests => 49; +use Test::More tests => 61; BEGIN { use_ok("IkiWiki"); } @@ -82,4 +82,33 @@ foreach my $spec ("bar or (backlink(foo) and !*.png)", "backlink(foo)") { ok($IkiWiki::depends{foo2}{$spec} & $IkiWiki::DEPEND_CONTENT); ok(! ($IkiWiki::depends{foo2}{$spec} & ($IkiWiki::DEPEND_PRESENCE | $IkiWiki::DEPEND_LINKS))); ok($IkiWiki::depends_simple{foo2}{foo} == $IkiWiki::DEPEND_LINKS); + %IkiWiki::depends_simple=(); + %IkiWiki::depends=(); +} + +TODO: { + local $TODO = "optimisation not yet written"; + +# a pagespec that hard fails due to a glob, etc, will not set influences +# for other terms that normally would. +foreach my $spec ("nosuchpage and link(bar)", "link(bar) and */Discussion") { + pagespec_match_list("foo2", $spec, deptype => deptype("presence")); + ok($IkiWiki::depends{foo2}{$spec} & $IkiWiki::DEPEND_PRESENCE); + ok(! ($IkiWiki::depends{foo2}{$spec} & ($IkiWiki::DEPEND_CONTENT | $IkiWiki::DEPEND_LINKS))); + ok(! exists $IkiWiki::depends_simple{foo2}{foo2}); + %IkiWiki::depends_simple=(); + %IkiWiki::depends=(); +} + +# a pagespec containing a hard failure that is ored with another term will +# get influences from the other term +foreach my $spec ("nosuchpage or link(bar)", "link(bar) or */Discussion") { + pagespec_match_list("foo2", $spec, deptype => deptype("presence")); + ok($IkiWiki::depends{foo2}{$spec} & $IkiWiki::DEPEND_PRESENCE); + ok(! ($IkiWiki::depends{foo2}{$spec} & ($IkiWiki::DEPEND_CONTENT | $IkiWiki::DEPEND_LINKS))); + ok($IkiWiki::depends_simple{foo2}{foo2} == $IkiWiki::DEPEND_LINKS); + %IkiWiki::depends_simple=(); + %IkiWiki::depends=(); +} + } diff --git a/t/pagespec_match_result.t b/t/pagespec_match_result.t index c2112bf14..d9c31d6f0 100755 --- a/t/pagespec_match_result.t +++ b/t/pagespec_match_result.t @@ -57,21 +57,3 @@ ok(! $s->influences->{foo}, "removed 0 influence"); ok(! $s->influences->{bar}, "removed 1 influence"); ok($s->influences->{baz}, "set influence"); ok($s->influences_static); - -# influence blocking -my $r=F()->block & S(foo => 1); -ok(! $r->influences->{foo}, "failed blocker & influence -> does not pass"); -$r=F()->block | S(foo => 1); -ok($r->influences->{foo}, "failed blocker | influence -> does pass"); -$r=S(foo => 1) & F()->block; -ok(! $r->influences->{foo}, "influence & failed blocker -> does not pass"); -$r=S(foo => 1) | F()->block; -ok($r->influences->{foo}, "influence | failed blocker -> does pass"); -$r=S(foo => 1) & F()->block & S(foo => 2); -ok(! $r->influences->{foo}, "influence & failed blocker & influence -> does not pass"); -$r=S(foo => 1) | F()->block | S(foo => 2); -ok($r->influences->{foo}, "influence | failed blocker | influence -> does pass"); -$r=S()->block & S(foo => 1); -ok($r->influences->{foo}, "successful blocker -> does pass"); -$r=(! S()->block) & S(foo => 1); -ok(! $r->influences->{foo}, "! successful blocker -> failed blocker"); -- cgit v1.2.3 From 7e7953f0e240bc0e9201942dd88a4f911904d151 Mon Sep 17 00:00:00 2001 From: Joey Hess Date: Mon, 12 Oct 2009 00:05:31 -0400 Subject: formatting --- doc/ikiwiki-calendar.mdwn | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/ikiwiki-calendar.mdwn b/doc/ikiwiki-calendar.mdwn index 3f5c6a29e..982892fca 100644 --- a/doc/ikiwiki-calendar.mdwn +++ b/doc/ikiwiki-calendar.mdwn @@ -28,7 +28,7 @@ Specify a second year to create pages for a span of years. Existing pages will not be overwritten by this command by default. Use the `-f` switch to force it to overwrite any existing pages. -## CRONTAB +# CRONTAB While this command only needs to be run once a year to update the archive pages for each new year, you are recommended to set up -- cgit v1.2.3 From e82b43bf950e1ff11683ae96abdd29879f92488a Mon Sep 17 00:00:00 2001 From: Joey Hess Date: Mon, 12 Oct 2009 00:50:48 -0400 Subject: skip merges git log --follow seems to sometimes show merges from before the file was ever created. So, skip them, a file shouldn't be first created during a merge anyway. --- IkiWiki/Plugin/git.pm | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/IkiWiki/Plugin/git.pm b/IkiWiki/Plugin/git.pm index 9ecda4ffb..c5c83a3a7 100644 --- a/IkiWiki/Plugin/git.pm +++ b/IkiWiki/Plugin/git.pm @@ -613,7 +613,8 @@ sub rcs_getctime ($) { # Remove srcdir prefix $file =~ s/^\Q$config{srcdir}\E\/?//; - my @raw_lines = run_or_die('git', 'log', '--follow', + my @raw_lines = run_or_die('git', 'log', + '--follow', '--no-merges', '--pretty=raw', '--raw', '--abbrev=40', '--always', '-c', '-r', '--', $file); my @ci; -- cgit v1.2.3 From 11e6d650eae4377485cb83f61a0ce9519ceb4c57 Mon Sep 17 00:00:00 2001 From: Joey Hess Date: Mon, 12 Oct 2009 12:19:42 -0400 Subject: calendar: Fix CSS for year calendar to match the plugin documentation. The names in the documentation were completly different, but also seemed better chosen than the names in the code. --- IkiWiki/Plugin/calendar.pm | 13 ++++--------- debian/changelog | 1 + 2 files changed, 5 insertions(+), 9 deletions(-) diff --git a/IkiWiki/Plugin/calendar.pm b/IkiWiki/Plugin/calendar.pm index e3c5e2f2d..71c671d67 100644 --- a/IkiWiki/Plugin/calendar.pm +++ b/IkiWiki/Plugin/calendar.pm @@ -300,21 +300,16 @@ EOF my $tag; my $mtag=sprintf("%02d", $month); if ($month == $params{month}) { - if ($pagesources{"$archivebase/$params{year}/$mtag"}) { - $tag = 'this_month_link'; - } - else { - $tag = 'this_month_nolink'; - } + $tag = 'year-calendar-this-month'; } elsif ($pagesources{"$archivebase/$params{year}/$mtag"}) { - $tag = 'month_link'; + $tag = 'year-calendar-month-link'; } elsif ($future_month && $month >= $future_month) { - $tag = 'month_future'; + $tag = 'year-calendar-month-future'; } else { - $tag = 'month_nolink'; + $tag = 'year-calendar-month-nolink'; } if ($pagesources{"$archivebase/$params{year}/$mtag"}) { diff --git a/debian/changelog b/debian/changelog index e9f09a8c6..b9d1923cd 100644 --- a/debian/changelog +++ b/debian/changelog @@ -34,6 +34,7 @@ ikiwiki (3.2009XXXX) UNRELEASED; urgency=low linked to an archive page from the wrong year, or were missing. * git: --getctime will now follow renames back to the original creation of a file. + * calendar: Fix CSS for year calendar to match the plugin documentation. -- Joey Hess Fri, 09 Oct 2009 19:53:50 -0400 -- cgit v1.2.3 From 6678ab8fb3c956ea52d08e546cea7c8e3204aefb Mon Sep 17 00:00:00 2001 From: Joey Hess Date: Mon, 12 Oct 2009 12:21:46 -0400 Subject: Added minimal default CSS for calendar plugin, just highlighting the current day. --- debian/changelog | 2 ++ doc/style.css | 5 ++++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/debian/changelog b/debian/changelog index b9d1923cd..ef92e48fc 100644 --- a/debian/changelog +++ b/debian/changelog @@ -35,6 +35,8 @@ ikiwiki (3.2009XXXX) UNRELEASED; urgency=low * git: --getctime will now follow renames back to the original creation of a file. * calendar: Fix CSS for year calendar to match the plugin documentation. + * Added minimal default CSS for calendar plugin, just highlighting the + current day. -- Joey Hess Fri, 09 Oct 2009 19:53:50 -0400 diff --git a/doc/style.css b/doc/style.css index 4770fc942..be86a0818 100644 --- a/doc/style.css +++ b/doc/style.css @@ -403,7 +403,6 @@ span.color { } /* Used by the highlight plugin. */ - pre.hl { color:#000000; background-color:#ffffff; } .hl.num { color:#2928ff; } .hl.esc { color:#ff00ff; } @@ -419,3 +418,7 @@ pre.hl { color:#000000; background-color:#ffffff; } .hl.kwb { color:#830000; } .hl.kwc { color:#000000; font-weight:bold; } .hl.kwd { color:#010181; } + +/* For the calendar plugin. */ +.month-calendar-day-this-day { background-color: #eee; } +.year-calendar-this-month { background-color: #eee; } -- cgit v1.2.3 From 227540fd875bfaa6b810c0d7caa346f32d5bd7ce Mon Sep 17 00:00:00 2001 From: Joey Hess Date: Mon, 12 Oct 2009 12:30:10 -0400 Subject: calendar: Add creation time limits to user's pagespec This avoids all calendars rebuilding when a new page is added that will only show in one of them. --- IkiWiki/Plugin/calendar.pm | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/IkiWiki/Plugin/calendar.pm b/IkiWiki/Plugin/calendar.pm index 71c671d67..5aac95884 100644 --- a/IkiWiki/Plugin/calendar.pm +++ b/IkiWiki/Plugin/calendar.pm @@ -66,7 +66,8 @@ sub format_month (@) { my %params=@_; my %linkcache; - foreach my $p (pagespec_match_list($params{page}, $params{pages}, + foreach my $p (pagespec_match_list($params{page}, + "creation_year($params{year}) and creation_month($params{month}) and ($params{pages})", # add presence dependencies to update # month calendar when pages are added/removed deptype => deptype("presence"))) { -- cgit v1.2.3 From 22737e53f1b0367bc9bfb8d7bcbfc4dcc08a81ae Mon Sep 17 00:00:00 2001 From: Joey Hess Date: Mon, 12 Oct 2009 14:05:56 -0400 Subject: remove whitespace from within arrow links --- IkiWiki/Plugin/calendar.pm | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/IkiWiki/Plugin/calendar.pm b/IkiWiki/Plugin/calendar.pm index 5aac95884..d5a80795a 100644 --- a/IkiWiki/Plugin/calendar.pm +++ b/IkiWiki/Plugin/calendar.pm @@ -136,7 +136,7 @@ sub format_month (@) { $purl = htmllink($params{page}, $params{destpage}, "$archivebase/$pyear/$pmonth", noimageinline => 1, - linktext => " \&larr "); + linktext => "\&larr"); } add_depends($params{page}, "$archivebase/$pyear/$pmonth", deptype("presence")); @@ -144,7 +144,7 @@ sub format_month (@) { $nurl = htmllink($params{page}, $params{destpage}, "$archivebase/$nyear/$nmonth", noimageinline => 1, - linktext => " \&rarr "); + linktext => "\&rarr"); } add_depends($params{page}, "$archivebase/$nyear/$nmonth", deptype("presence")); -- cgit v1.2.3 From 5c78192435210cdb7792ed56b04c2ef24a2d2127 Mon Sep 17 00:00:00 2001 From: Joey Hess Date: Mon, 12 Oct 2009 14:19:04 -0400 Subject: year calendar: only link to months that have posts This does mean the year calendars depend on existence of all posts made in the year and have to be updated. --- IkiWiki/Plugin/calendar.pm | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/IkiWiki/Plugin/calendar.pm b/IkiWiki/Plugin/calendar.pm index d5a80795a..ddcd1a823 100644 --- a/IkiWiki/Plugin/calendar.pm +++ b/IkiWiki/Plugin/calendar.pm @@ -242,6 +242,20 @@ EOF sub format_year (@) { my %params=@_; + + my @post_months; + foreach my $p (pagespec_match_list($params{page}, + "creation_year($params{year}) and ($params{pages})", + # add presence dependencies to update + # year calendar's links to months when + # pages are added/removed + deptype => deptype("presence"))) { + my $mtime = $IkiWiki::pagectime{$p}; + my @date = localtime($mtime); + my $month = $date[4] + 1; + + $post_months[$month]++; + } my $calendar="\n"; @@ -313,7 +327,8 @@ EOF $tag = 'year-calendar-month-nolink'; } - if ($pagesources{"$archivebase/$params{year}/$mtag"}) { + if ($pagesources{"$archivebase/$params{year}/$mtag"} && + $post_months[$mtag]) { $murl = htmllink($params{page}, $params{destpage}, "$archivebase/$params{year}/$mtag", noimageinline => 1, -- cgit v1.2.3 From 28c4caea59543b6d8fd0c62ff5a60aff67a9bba7 Mon Sep 17 00:00:00 2001 From: Joey Hess Date: Mon, 12 Oct 2009 14:22:48 -0400 Subject: year calendar: Avoid highlighting the current month in a different year --- IkiWiki/Plugin/calendar.pm | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/IkiWiki/Plugin/calendar.pm b/IkiWiki/Plugin/calendar.pm index ddcd1a823..c9bdf4a17 100644 --- a/IkiWiki/Plugin/calendar.pm +++ b/IkiWiki/Plugin/calendar.pm @@ -262,8 +262,9 @@ sub format_year (@) { my $pyear = $params{year} - 1; my $nyear = $params{year} + 1; + my $thisyear = $now[5]+1900; my $future_month = 0; - $future_month = $now[4]+1 if ($params{year} == $now[5]+1900); + $future_month = $now[4]+1 if $params{year} == $thisyear; my $archivebase = 'archives'; $archivebase = $config{archivebase} if defined $config{archivebase}; @@ -314,7 +315,7 @@ EOF $calendar.=qq{\t\n} if ($month % $params{months_per_row} == 1); my $tag; my $mtag=sprintf("%02d", $month); - if ($month == $params{month}) { + if ($month == $params{month} && $thisyear == $params{year}) { $tag = 'year-calendar-this-month'; } elsif ($pagesources{"$archivebase/$params{year}/$mtag"}) { -- cgit v1.2.3 From 5e4e43e2c73d6077f8091fe063add1ebce9335e3 Mon Sep 17 00:00:00 2001 From: Joey Hess Date: Tue, 13 Oct 2009 13:33:51 -0400 Subject: match_link: dynamic influence needed for page that currently has no links --- IkiWiki.pm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/IkiWiki.pm b/IkiWiki.pm index cd93fe969..2847c7e0f 100644 --- a/IkiWiki.pm +++ b/IkiWiki.pm @@ -2168,7 +2168,7 @@ sub match_link ($$;@) { my $from=exists $params{location} ? $params{location} : ''; my $links = $IkiWiki::links{$page}; - return IkiWiki::FailReason->new("$page has no links") + return IkiWiki::FailReason->new("$page has no links", "" => 1) unless $links && @{$links}; my $bestlink = IkiWiki::bestlink($from, $link); foreach my $p (@{$links}) { -- cgit v1.2.3 From a20bc7a3fc6a2f2369022873ef7c2afbd5e49105 Mon Sep 17 00:00:00 2001 From: Joey Hess Date: Tue, 13 Oct 2009 14:37:14 -0400 Subject: influence blocker implementation This avoids unnecessary influences being recorded from pagespecs such as "link(done) and bugs/*", when a page cannot ever possibly match. A pagespec term that returns a value without influence is an influence blocker. If such a blocker has a false value (possibly due to being negated) and is ANDed with another term, it blocks that term's influence from propigating out. If the term is ORed, or has a true value, it does not block influence. (Consider "link(done) or bugs/*" and "link(done) and !nosuchpage") In the implementation in merge_influence, I had to be careful to never negate $this or $other when testing if they are an influence blocker, since negation mutates the object. Thus the slightly weird if statement. --- IkiWiki.pm | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/IkiWiki.pm b/IkiWiki.pm index 2847c7e0f..ac01ea418 100644 --- a/IkiWiki.pm +++ b/IkiWiki.pm @@ -2071,7 +2071,7 @@ use overload ( '""' => sub { $_[0][0] }, '0+' => sub { 0 }, '!' => sub { bless $_[0], 'IkiWiki::SuccessReason'}, - '&' => sub { $_[0]->merge_influences($_[1]); $_[0] }, + '&' => sub { $_[0]->merge_influences($_[1], 1); $_[0] }, '|' => sub { $_[1]->merge_influences($_[0]); $_[1] }, fallback => 1, ); @@ -2084,7 +2084,7 @@ use overload ( '""' => sub { $_[0][0] }, '0+' => sub { 1 }, '!' => sub { bless $_[0], 'IkiWiki::FailReason'}, - '&' => sub { $_[1]->merge_influences($_[0]); $_[1] }, + '&' => sub { $_[1]->merge_influences($_[0], 1); $_[1] }, '|' => sub { $_[0]->merge_influences($_[1]); $_[0] }, fallback => 1, ); @@ -2110,8 +2110,20 @@ sub influences_static { sub merge_influences { my $this=shift; my $other=shift; - foreach my $influence (keys %{$other->[1]}) { - $this->[1]{$influence} |= $other->[1]{$influence}; + my $anded=shift; + + if (! $anded || (($this || %{$this->[1]}) && + ($other || %{$other->[1]}))) { + foreach my $influence (keys %{$other->[1]}) { + $this->[1]{$influence} |= $other->[1]{$influence}; + } + } + else { + # influence blocker + print STDERR "merging $this and $other; found influence blocker\n"; + $this->[1]={}; + $this->[2]=1; + return; } } -- cgit v1.2.3 From 2f5beb59bff17ace9e33743d646a95204a9be5bc Mon Sep 17 00:00:00 2001 From: Joey Hess Date: Tue, 13 Oct 2009 14:46:38 -0400 Subject: tests for influence blocking --- t/pagespec_match_list.t | 24 +++++++++++------------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/t/pagespec_match_list.t b/t/pagespec_match_list.t index 51145a973..dd5dcc5b0 100755 --- a/t/pagespec_match_list.t +++ b/t/pagespec_match_list.t @@ -1,7 +1,7 @@ #!/usr/bin/perl use warnings; use strict; -use Test::More tests => 61; +use Test::More tests => 88; BEGIN { use_ok("IkiWiki"); } @@ -86,23 +86,23 @@ foreach my $spec ("bar or (backlink(foo) and !*.png)", "backlink(foo)") { %IkiWiki::depends=(); } -TODO: { - local $TODO = "optimisation not yet written"; - -# a pagespec that hard fails due to a glob, etc, will not set influences -# for other terms that normally would. -foreach my $spec ("nosuchpage and link(bar)", "link(bar) and */Discussion") { +# Hard fails due to a glob, etc, will block influences of other anded terms. +foreach my $spec ("nosuchpage and link(bar)", "link(bar) and nosuchpage", + "link(bar) and */Discussion", "*/Discussion and link(bar)", + "!foo2 and link(bar)", "link(bar) and !foo2") { pagespec_match_list("foo2", $spec, deptype => deptype("presence")); ok($IkiWiki::depends{foo2}{$spec} & $IkiWiki::DEPEND_PRESENCE); ok(! ($IkiWiki::depends{foo2}{$spec} & ($IkiWiki::DEPEND_CONTENT | $IkiWiki::DEPEND_LINKS))); - ok(! exists $IkiWiki::depends_simple{foo2}{foo2}); + ok(! exists $IkiWiki::depends_simple{foo2}{foo2}, "no influence from $spec"); %IkiWiki::depends_simple=(); %IkiWiki::depends=(); } -# a pagespec containing a hard failure that is ored with another term will -# get influences from the other term -foreach my $spec ("nosuchpage or link(bar)", "link(bar) or */Discussion") { +# A hard fail will not block influences of other ored terms. +foreach my $spec ("nosuchpage or link(bar)", "link(bar) or nosuchpage", + "link(bar) or */Discussion", "*/Discussion or link(bar)", + "!foo2 or link(bar)", "link(bar) or !foo2", + "link(bar) or (!foo2 and !foo1)") { pagespec_match_list("foo2", $spec, deptype => deptype("presence")); ok($IkiWiki::depends{foo2}{$spec} & $IkiWiki::DEPEND_PRESENCE); ok(! ($IkiWiki::depends{foo2}{$spec} & ($IkiWiki::DEPEND_CONTENT | $IkiWiki::DEPEND_LINKS))); @@ -110,5 +110,3 @@ foreach my $spec ("nosuchpage or link(bar)", "link(bar) or */Discussion") { %IkiWiki::depends_simple=(); %IkiWiki::depends=(); } - -} -- cgit v1.2.3 From c916dcd035ef35e545119c91953a135600ecf0c3 Mon Sep 17 00:00:00 2001 From: Joey Hess Date: Tue, 13 Oct 2009 14:58:22 -0400 Subject: fix some broken influence blocking testing, add more tests --- t/pagespec_match_result.t | 41 +++++++++++++++++++++++++++++++++-------- 1 file changed, 33 insertions(+), 8 deletions(-) diff --git a/t/pagespec_match_result.t b/t/pagespec_match_result.t index d9c31d6f0..13fcdcad0 100755 --- a/t/pagespec_match_result.t +++ b/t/pagespec_match_result.t @@ -1,7 +1,7 @@ #!/usr/bin/perl use warnings; use strict; -use Test::More tests => 71; +use Test::More tests => 138; BEGIN { use_ok("IkiWiki"); } @@ -34,10 +34,27 @@ ok(!(S() & F())); ok(!(S() & F() & E())); ok(S() & (F() | F() | S())); -# influences are always merged, no matter the operation performed, -# as long as the two items are always both present -foreach my $op ('$s | $f', '$s & $f', '$s & $f & E()', '$s | E() | $f', - '! $s | ! $f', '!(!(!$s)) | $f') { +# influence merging tests +foreach my $test ( + ['$s | $f' => 1], # OR merges + ['! $s | ! $f' => 1], # OR merges with negated terms too + ['!(!(!$s)) | $f' => 1],# OR merges with multiple negation too + ['$s | $f | E()' => 1], # OR merges, even though E() has no influences + ['$s | E() | $f' => 1], # ditto + ['E() | $s | $f' => 1], # ditto + ['!$s | !$f | E()' => 1],# negated terms also do not block merges + ['!$s | E() | $f' => 1],# ditto + ['E() | $s | !$f' => 1],# ditto + ['$s & $f' => 1], # AND merges if both items have influences + ['!$s & $f' => 1], # AND merges negated terms too + ['$s & !$f' => 1], # AND merges negated terms too + ['$s & $f & E()' => 0], # AND fails to merge since E() has no influences + ['$s & E() & $f' => 0], # ditto + ['E() & $s & $f' => 0], # ditto + ) { + my $op=$test->[0]; + my $influence=$test->[1]; + my $s=S(foo => 1, bar => 1); is($s->influences->{foo}, 1); is($s->influences->{bar}, 1); @@ -46,9 +63,14 @@ foreach my $op ('$s | $f', '$s & $f', '$s & $f & E()', '$s | E() | $f', is($f->influences->{baz}, 1); my $c = eval $op; ok(ref $c); - is($c->influences->{foo}, 1, "foo ($op)"); - is($c->influences->{bar}, (1 | 2), "bar ($op)"); - is($c->influences->{baz}, 1, "baz ($op)"); + if ($influence) { + is($c->influences->{foo}, 1, "foo ($op)"); + is($c->influences->{bar}, (1 | 2), "bar ($op)"); + is($c->influences->{baz}, 1, "baz ($op)"); + } + else { + ok(! %{$c->influences}, "no influence for ($op)"); + } } my $s=S(foo => 0, bar => 1); @@ -57,3 +79,6 @@ ok(! $s->influences->{foo}, "removed 0 influence"); ok(! $s->influences->{bar}, "removed 1 influence"); ok($s->influences->{baz}, "set influence"); ok($s->influences_static); +$s=S(foo => 0, bar => 1); +$s->influences(baz => 1, "" => 1); +ok(! $s->influences_static); -- cgit v1.2.3 From 046ac5fec5534e10b8e34b96014f936bb151d147 Mon Sep 17 00:00:00 2001 From: Joey Hess Date: Tue, 13 Oct 2009 15:00:07 -0400 Subject: remove debugging and cruft --- IkiWiki.pm | 3 --- 1 file changed, 3 deletions(-) diff --git a/IkiWiki.pm b/IkiWiki.pm index ac01ea418..1e9d1ca2a 100644 --- a/IkiWiki.pm +++ b/IkiWiki.pm @@ -2120,10 +2120,7 @@ sub merge_influences { } else { # influence blocker - print STDERR "merging $this and $other; found influence blocker\n"; $this->[1]={}; - $this->[2]=1; - return; } } -- cgit v1.2.3