X-Git-Url: http://git.vanrenterghem.biz/git.ikiwiki.info.git/blobdiff_plain/59ad31c24220f16c6aa52d187ecca215c914831c..fd7b5767d3d377185838895d04f51288f0889a59:/IkiWiki/Render.pm diff --git a/IkiWiki/Render.pm b/IkiWiki/Render.pm index 85ae0f8e9..fe0b3138a 100644 --- a/IkiWiki/Render.pm +++ b/IkiWiki/Render.pm @@ -210,7 +210,7 @@ sub render ($) { if (defined $type) { my $page=pagename($file); delete $depends{$page}; - delete $depends_exact{$page}; + delete $depends_simple{$page}; will_render($page, htmlpage($page), 1); return if $type=~/^_/; @@ -225,7 +225,7 @@ sub render ($) { } else { delete $depends{$file}; - delete $depends_exact{$file}; + delete $depends_simple{$file}; will_render($file, $file, 1); if ($config{hardlink}) { @@ -342,7 +342,8 @@ 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); @@ -406,10 +407,11 @@ sub refresh () { $stat[9] > $pagemtime{$page} || $forcerebuild{$page}) { $pagemtime{$page}=$stat[9]; + if (isinternal($page)) { - push @internal, $file; # Preprocess internal page in scan-only mode. preprocess($page, $page, readfile($srcfile), 1); + push @internal_change, $file; } else { push @needsbuild, $file; @@ -418,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); @@ -429,11 +443,11 @@ 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}; - delete $depends_exact{$page}; + delete $depends_simple{$page}; foreach my $old (@{$renderedfiles{$page}}) { delete $destsources{$old}; } @@ -453,27 +467,66 @@ sub refresh () { } } } - - if (%rendered || @del || @internal) { + + # 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 %lcchanged = map { lc(pagename($_)) => 1 } @changed; - - # rebuild dependant pages + my @exists_changed=(@add, @del); + + 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; - - if (exists $depends_exact{$p}) { - foreach my $d (keys %{$depends_exact{$p}}) { - if (exists $lcchanged{$d}) { + + 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); @@ -482,58 +535,52 @@ sub refresh () { # only consider internal files # if the page explicitly depends # on such files - foreach my $file (@changed, $d =~ /internal\(/ ? @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; } } } } - + if (defined $reason) { debug(sprintf(gettext("building %s, which depends on %s"), $f, $reason)); render($f); $rendered{$f}=1; + $deps=1; + last; } } - - # 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) { - 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; - } + } 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; } }