]> git.vanrenterghem.biz Git - git.ikiwiki.info.git/blobdiff - IkiWiki/Plugin/aggregate.pm
+1
[git.ikiwiki.info.git] / IkiWiki / Plugin / aggregate.pm
index 59185e97ffdd43eb283fbbf2d454cbbb40b3d894..8f0870e2eea27257135aef9d5daaf6731c036506 100644 (file)
@@ -16,7 +16,8 @@ my %guids;
 sub import {
        hook(type => "getopt", id => "aggregate", call => \&getopt);
        hook(type => "getsetup", id => "aggregate", call => \&getsetup);
-       hook(type => "checkconfig", id => "aggregate", call => \&checkconfig);
+       hook(type => "checkconfig", id => "aggregate", call => \&checkconfig,
+               last => 1);
        hook(type => "needsbuild", id => "aggregate", call => \&needsbuild);
        hook(type => "preprocess", id => "aggregate", call => \&preprocess);
         hook(type => "delete", id => "aggregate", call => \&delete);
@@ -64,6 +65,8 @@ sub checkconfig () {
                $config{aggregateinternal}=1;
        }
 
+       # This is done here rather than in a refresh hook because it
+       # needs to run before the wiki is locked.
        if ($config{aggregate} && ! ($config{post_commit} && 
                                     IkiWiki::commit_hook_enabled())) {
                launchaggregation();
@@ -101,8 +104,7 @@ sub launchaggregation () {
        my @feeds=needsaggregate();
        return unless @feeds;
        if (! lockaggregate()) {
-               debug("an aggregation process is already running");
-               return;
+               error("an aggregation process is already running");
        }
        # force a later rebuild of source pages
        $IkiWiki::forcerebuild{$_->{sourcepage}}=1
@@ -162,10 +164,14 @@ sub migrate_to_internal {
                
                $config{aggregateinternal} = 0;
                my $oldname = "$config{srcdir}/".htmlfn($data->{page});
+               if (! -e $oldname) {
+                       $oldname = $IkiWiki::Plugin::transient::transientdir."/".htmlfn($data->{page});
+               }
+
                my $oldoutput = $config{destdir}."/".IkiWiki::htmlpage($data->{page});
                
                $config{aggregateinternal} = 1;
-               my $newname = "$config{srcdir}/".htmlfn($data->{page});
+               my $newname = $IkiWiki::Plugin::transient::transientdir."/".htmlfn($data->{page});
                
                debug "moving $oldname -> $newname";
                if (-e $newname) {
@@ -185,7 +191,7 @@ sub migrate_to_internal {
                if (-e $oldoutput) {
                        require IkiWiki::Render;
                        debug("removing output file $oldoutput");
-                       IkiWiki::prune($oldoutput);
+                       IkiWiki::prune($oldoutput, $config{destdir});
                }
        }
        
@@ -385,13 +391,16 @@ sub garbage_collect () {
        foreach my $guid (values %guids) {
                # any guid whose feed is gone should be removed
                if (! exists $feeds{$guid->{feed}}) {
-                       unlink "$config{srcdir}/".htmlfn($guid->{page})
-                               if exists $guid->{page};
+                       if (exists $guid->{page}) {
+                               unlink $IkiWiki::Plugin::transient::transientdir."/".htmlfn($guid->{page})
+                                       || unlink "$config{srcdir}/".htmlfn($guid->{page});
+                       }
                        delete $guids{$guid->{guid}};
                }
                # handle expired guids
                elsif ($guid->{expired} && exists $guid->{page}) {
                        unlink "$config{srcdir}/".htmlfn($guid->{page});
+                       unlink $IkiWiki::Plugin::transient::transientdir."/".htmlfn($guid->{page});
                        delete $guid->{page};
                        delete $guid->{md5};
                }
@@ -479,6 +488,7 @@ sub needsaggregate () {
 }
 
 sub aggregate (@) {
+       eval q{use Net::INET6Glue::INET_is_INET6}; # may not be available
        eval q{use XML::Feed};
        error($@) if $@;
        eval q{use URI::Fetch};
@@ -503,7 +513,11 @@ sub aggregate (@) {
                        }
                        $feed->{feedurl}=pop @urls;
                }
-               my $res=URI::Fetch->fetch($feed->{feedurl});
+               # Using the for_url parameter makes sure we crash if used
+               # with an older IkiWiki.pm that didn't automatically try
+               # to use LWPx::ParanoidAgent.
+               my $ua=useragent(for_url => $feed->{feedurl});
+               my $res=URI::Fetch->fetch($feed->{feedurl}, UserAgent=>$ua);
                if (! $res) {
                        $feed->{message}=URI::Fetch->errstr;
                        $feed->{error}=1;
@@ -542,7 +556,9 @@ sub aggregate (@) {
                        };
                }
                if ($@) {
-                       $feed->{message}=gettext("feed crashed XML::Feed!")." ($@)";
+                       # gettext can clobber $@
+                       my $error = $@;
+                       $feed->{message}=gettext("feed crashed XML::Feed!")." ($error)";
                        $feed->{error}=1;
                        debug($feed->{message});
                        next;
@@ -558,7 +574,9 @@ sub aggregate (@) {
                        # XML::Feed doesn't work around XML::Atom's bizarre
                        # API, so we will. Real unicode strings? Yes please.
                        # See [[bugs/Aggregated_Atom_feeds_are_double-encoded]]
+                       no warnings 'once';
                        local $XML::Atom::ForceUnicode = 1;
+                       use warnings;
 
                        my $c=$entry->content;
                        # atom feeds may have no content, only a summary
@@ -570,6 +588,7 @@ sub aggregate (@) {
                                feed => $feed,
                                copyright => $f->copyright,
                                title => defined $entry->title ? decode_entities($entry->title) : "untitled",
+                               author => defined $entry->author ? decode_entities($entry->author) : "",
                                link => $entry->link,
                                content => (defined $c && defined $c->body) ? $c->body : "",
                                guid => defined $entry->id ? $entry->id : time."_".$feed->{name},
@@ -590,6 +609,7 @@ sub add_page (@) {
                # updating an existing post
                $guid=$guids{$params{guid}};
                return if $guid->{expired};
+               write_page($feed, $guid, $mtime, \%params);
        }
        else {
                # new post
@@ -604,32 +624,46 @@ sub add_page (@) {
                # escape slashes and periods in title so it doesn't specify
                # directory name or trigger ".." disallowing code.
                $page=~s!([/.])!"__".ord($1)."__"!eg;
-               $page=$feed->{dir}."/".$page;
-               ($page)=$page=~/$config{wiki_file_regexp}/;
                if (! defined $page || ! length $page) {
                        $page=$feed->{dir}."/item";
                }
+               $page=$feed->{dir}."/".$page;
+               ($page)=$page=~/$config{wiki_file_regexp}/;
                my $c="";
                while (exists $IkiWiki::pagecase{lc $page.$c} ||
+                      -e $IkiWiki::Plugin::transient::transientdir."/".htmlfn($page.$c) ||
                       -e "$config{srcdir}/".htmlfn($page.$c)) {
                        $c++
                }
+               $page=$page.$c;
 
-               # Make sure that the file name isn't too long. 
-               # NB: This doesn't check for path length limits.
-               my $max=POSIX::pathconf($config{srcdir}, &POSIX::_PC_NAME_MAX);
-               if (defined $max && length(htmlfn($page)) >= $max) {
+               $guid->{page}=$page;
+               eval { write_page($feed, $guid, $mtime, \%params) };
+               if ($@) {
+                       # assume failure was due to a too long filename
                        $c="";
                        $page=$feed->{dir}."/item";
                        while (exists $IkiWiki::pagecase{lc $page.$c} ||
-                              -e "$config{srcdir}/".htmlfn($page.$c)) {
+                             -e $IkiWiki::Plugin::transient::transientdir."/".htmlfn($page.$c) ||
+                             -e "$config{srcdir}/".htmlfn($page.$c)) {
                                $c++
                        }
+                       $page=$page.$c;
+
+                       $guid->{page}=$page;
+                       write_page($feed, $guid, $mtime, \%params);
                }
 
-               $guid->{page}=$page;
                debug(sprintf(gettext("creating new page %s"), $page));
        }
+}
+
+sub write_page ($$$$$) {
+       my $feed=shift;
+       my $guid=shift;
+       my $mtime=shift;
+       my %params=%{shift()};
+
        $guid->{feed}=$feed->{name};
        
        # To write or not to write? Need to avoid writing unchanged pages
@@ -648,11 +682,16 @@ sub add_page (@) {
                $template=template($feed->{template}, blind_cache => 1);
        };
        if ($@) {
-               print STDERR gettext("failed to process template:")." $@";
+               # gettext can clobber $@
+               my $error = $@;
+               print STDERR gettext("failed to process template:")." $error";
                return;
        }
        $template->param(title => $params{title})
                if defined $params{title} && length($params{title});
+       $template->param(author => $params{author})
+               if defined $params{author} && length($params{author}
+                       && $params{author} ne $feed->{name});
        $template->param(content => wikiescape(htmlabs($params{content},
                defined $params{base} ? $params{base} : $feed->{feedurl})));
        $template->param(name => $feed->{name});
@@ -664,13 +703,14 @@ sub add_page (@) {
        if (ref $feed->{tags}) {
                $template->param(tags => [map { tag => $_ }, @{$feed->{tags}}]);
        }
-       writefile(htmlfn($guid->{page}), $config{srcdir},
-               $template->output);
+       writefile(htmlfn($guid->{page}),
+               $IkiWiki::Plugin::transient::transientdir, $template->output);
 
        if (defined $mtime && $mtime <= time) {
                # Set the mtime, this lets the build process get the right
                # creation time on record for the new page.
-               utime $mtime, $mtime, "$config{srcdir}/".htmlfn($guid->{page});
+               utime $mtime, $mtime,
+                       $IkiWiki::Plugin::transient::transientdir."/".htmlfn($guid->{page});
                # Store it in pagectime for expiry code to use also.
                $IkiWiki::pagectime{$guid->{page}}=$mtime
                        unless exists $IkiWiki::pagectime{$guid->{page}};