implement links dependencies
authorJoey Hess <joey@gnu.kitenet.net>
Mon, 5 Oct 2009 18:08:46 +0000 (14:08 -0400)
committerJoey Hess <joey@gnu.kitenet.net>
Mon, 5 Oct 2009 18:33:23 +0000 (14:33 -0400)
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
IkiWiki/Render.pm

index 0bb0c1746075f755f7ae078f2730746164c48dd9..b895e12fc0a924fac01a6ef1b10d58e02dbdb003 100644 (file)
@@ -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) {
index 324ef24fadd22f2b11572f5331c0fd4a37d2d89f..4e8aae3bc8ea187cd82f0d8b17d17b84dfc9e2c8 100644 (file)
@@ -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};