* ikiwiki can now download and aggregate feeds with its new aggregate
authorjoey <joey@0fa5a96a-9a0e-0410-b3b2-a0fd24251071>
Sun, 30 Jul 2006 04:31:08 +0000 (04:31 +0000)
committerjoey <joey@0fa5a96a-9a0e-0410-b3b2-a0fd24251071>
Sun, 30 Jul 2006 04:31:08 +0000 (04:31 +0000)
  plugin, so it's possible to implement a Planet using ikiwiki!
* --setup --refresh no longer rebuilds wrappers. Use --setup --refresh
  --wrappers to do that.
* Add %IkiWiki::forcerebuild to provide a way for plugins like aggregate
  to update pages that haven't changed on disk.

21 files changed:
IkiWiki.pm
IkiWiki/Plugin/aggregate.pm [new file with mode: 0644]
IkiWiki/Plugin/skeleton.pm
IkiWiki/Render.pm
IkiWiki/Setup/Standard.pm
Makefile.PL
debian/changelog
debian/control
debian/postinst
doc/features.mdwn
doc/install.mdwn
doc/plugins.mdwn
doc/plugins/aggregate.mdwn [new file with mode: 0644]
doc/plugins/search.mdwn
doc/plugins/type/useful.mdwn [new file with mode: 0644]
doc/plugins/write.mdwn
doc/templates.mdwn
doc/todo/aggregation.mdwn
doc/usage.mdwn
ikiwiki
templates/aggregatepost.tmpl [new file with mode: 0644]

index c0b26e43fb33e77da03b36081effc1090de854bf..b5707195b9dcf7c3dd41241fa185cf547a48850b 100644 (file)
@@ -11,7 +11,7 @@ use Memoize;
 memoize("abs2rel");
 
 use vars qw{%config %links %oldlinks %oldpagemtime %pagectime
-            %renderedfiles %pagesources %depends %hooks};
+            %renderedfiles %pagesources %depends %hooks %forcerebuild};
 
 sub defaultconfig () { #{{{
        wiki_file_prune_regexp => qr{((^|/).svn/|\.\.|^\.|\/\.|\.html?$|\.rss$)},
diff --git a/IkiWiki/Plugin/aggregate.pm b/IkiWiki/Plugin/aggregate.pm
new file mode 100644 (file)
index 0000000..5c8151b
--- /dev/null
@@ -0,0 +1,300 @@
+#!/usr/bin/perl
+# Blog aggregation plugin.
+package IkiWiki::Plugin::aggregate;
+
+use warnings;
+use strict;
+use IkiWiki;
+
+my %feeds;
+my %guids;
+
+sub import { #{{{
+       IkiWiki::hook(type => "getopt", id => "aggregate", 
+               call => \&getopt);
+       IkiWiki::hook(type => "checkconfig", id => "aggregate",
+               call => \&checkconfig);
+       IkiWiki::hook(type => "filter", id => "aggregate", 
+               call => \&filter);
+       IkiWiki::hook(type => "preprocess", id => "aggregate",
+               call => \&preprocess);
+        IkiWiki::hook(type => "delete", id => "aggregate",
+                call => \&delete);
+       IkiWiki::hook(type => "savestate", id => "aggregate",
+               call => \&savestate);
+} # }}}
+
+sub getopt () { #{{{
+        eval q{use Getopt::Long};
+        Getopt::Long::Configure('pass_through');
+        GetOptions("aggregate" => \$IkiWiki::config{aggregate});
+} #}}}
+
+sub checkconfig () { #{{{
+       loadstate();
+       if ($IkiWiki::config{aggregate}) {
+               IkiWiki::loadindex();
+               aggregate();
+               savestate();
+       }
+} #}}}
+
+sub filter (@) { #{{{
+       my %params=@_;
+       my $page=$params{page};
+
+       # Mark all feeds originating on this page as removable;
+       # preprocess will unmark those that still exist.
+       remove_feeds($page);
+
+       return $params{content};
+} # }}}
+
+sub preprocess (@) { #{{{
+       my %params=@_;
+
+       foreach my $required (qw{name url dir}) {
+               if (! exists $params{$required}) {
+                       return "[[aggregate plugin missing $required parameter]]";
+               }
+       }
+
+       my $feed={};
+       my $name=$params{name};
+       if (exists $feeds{$name}) {
+               $feed=$feeds{$name};
+       }
+       else {
+               $feeds{$name}=$feed;
+       }
+       $feed->{name}=$name;
+       $feed->{sourcepage}=$params{page};
+       $feed->{url}=$params{url};
+       ($feed->{dir})=$params{dir}=~/$IkiWiki::config{wiki_file_regexp}/;
+       $feed->{dir}=~s/^\/+//;
+       $feed->{feedurl}=defined $params{feedurl} ? $params{feedurl} : $params{url};
+       $feed->{updateinterval}=defined $params{updateinterval} ? $params{updateinterval} : 15;
+       $feed->{expireage}=defined $params{expireage} ? $params{expireage} : 0;
+       $feed->{expirecount}=defined $params{expirecount} ? $params{expirecount} : 0;
+       delete $feed->{remove};
+       $feed->{lastupdate}=0 unless defined $feed->{lastupdate};
+       $feed->{numposts}=0 unless defined $feed->{numposts};
+       $feed->{newposts}=0 unless defined $feed->{newposts};
+       $feed->{message}="new feed" unless defined $feed->{message};
+       while (@_) {
+               my $key=shift;
+               my $value=shift;
+               if ($key eq 'tag') {
+                       push @{$feed->{tags}}, $value;
+               }
+       }
+
+       return "<a href=\"".$feed->{url}."\">".$feed->{name}."</a>: ".
+              "<i>".$feed->{message}."</i> (".$feed->{numposts}.
+              " stored posts; ".$feed->{newposts}." new)";
+} # }}}
+
+sub delete (@) { #{{{
+       my @files=@_;
+
+       # Remove feed data for removed pages.
+       foreach my $file (@files) {
+               my $page=IkiWiki::pagename($file);
+               remove_feeds($page);
+       }
+} #}}}
+
+sub loadstate () { #{{{
+       if (-e "$IkiWiki::config{wikistatedir}/aggregate") {
+               open (IN, "$IkiWiki::config{wikistatedir}/aggregate" ||
+                       die "$IkiWiki::config{wikistatedir}/aggregate: $!");
+               while (<IN>) {
+                       $_=IkiWiki::possibly_foolish_untaint($_);
+                       chomp;
+                       my $data={};
+                       foreach my $i (split(/ /, $_)) {
+                               my ($field, $val)=split(/=/, $i, 2);
+                               if ($field eq "name" || $field eq "message") {
+                                       $data->{$field}=IkiWiki::pagetitle($val);
+                               }
+                               elsif ($field eq "tag") {
+                                       push @{$data->{tags}}, $val;
+                               }
+                               else {
+                                       $data->{$field}=$val;
+                               }
+                       }
+                       
+                       if (exists $data->{name}) {
+                               $feeds{$data->{name}}=$data;
+                       }
+                       elsif (exists $data->{guid}) {
+                               $guids{$data->{guid}}=$data;
+                       }
+               }
+
+               close IN;
+       }
+} #}}}
+
+sub savestate () { #{{{
+       open (OUT, ">$IkiWiki::config{wikistatedir}/aggregate" ||
+               die "$IkiWiki::config{wikistatedir}/aggregate: $!");
+       foreach my $data (values %feeds, values %guids) {
+               if ($data->{remove}) {
+                       if ($data->{name}) {
+                               foreach my $guid (values %guids) {
+                                       if ($guid->{feed} eq $data->{name}) {
+                                               $guid->{remove}=1;
+                                       }
+                               }
+                       }
+                       else {
+                               unlink pagefile($data->{page});
+                       }
+                       next;
+               }
+
+               my @line;
+               foreach my $field (keys %$data) {
+                       if ($field eq "name" || $field eq "message") {
+                               push @line, "$field=".IkiWiki::titlepage($data->{$field});
+                       }
+                       elsif ($field eq "tags") {
+                               push @line, "tag=$_" foreach @{$data->{tags}};
+                       }
+                       else {
+                               push @line, "$field=".$data->{$field};
+                       }
+               }
+               print OUT join(" ", @line)."\n";
+       }
+       close OUT;
+} #}}}
+
+sub aggregate () { #{{{
+       eval q{use XML::Feed};
+       die $@ if $@;
+       eval q{use HTML::Entities};
+       die $@ if $@;
+
+FEED:  foreach my $feed (values %feeds) {
+               # TODO: check updateinterval
+               $feed->{lastupdate}=time;
+               $feed->{newposts}=0;
+               $IkiWiki::forcerebuild{$feed->{sourcepage}}=1;
+
+               IkiWiki::debug("checking feed ".$feed->{name}." ...");
+
+               my @urls=XML::Feed->find_feeds($feed->{feedurl});
+               if (! @urls) {
+                       $feed->{message}="could not find feed at ".$feed->{feedurl};
+                       IkiWiki::debug($feed->{message});
+               }
+               foreach my $url (@urls) {
+                       my $f=XML::Feed->parse(URI->new($url));
+                       if (! $f) {
+                               $feed->{message}=XML::Feed->errstr;
+                               IkiWiki::debug($feed->{message});
+                               next FEED;
+                       }
+
+                       foreach my $entry ($f->entries) {
+                               add_page(
+                                       feed => $feed,
+                                       title => decode_entities($entry->title),
+                                       link => $entry->link,
+                                       content => $entry->content->body,
+                                       guid => defined $entry->id ? $entry->id : time."_".$feed->name,
+                                       ctime => $entry->issued ? ($entry->issued->epoch || time) : time,
+                               );
+                       }
+               }
+               $feed->{message}="processed ok";
+       }
+
+       # TODO: expiry
+} #}}}
+
+sub add_page (@) { #{{{
+       my %params=@_;
+
+       my $feed=$params{feed};
+       my $guid={};
+       my $mtime;
+       if (exists $guids{$params{guid}}) {
+               # updating an existing post
+               $guid=$guids{$params{guid}};
+       }
+       else {
+               # new post
+               $guid->{guid}=$params{guid};
+               $guids{$params{guid}}=$guid;
+               $mtime=$params{ctime};
+               $feed->{numposts}++;
+               $feed->{newposts}++;
+
+               # assign it an unused page
+               my $page=$feed->{dir}."/".IkiWiki::titlepage($params{title});
+               ($page)=$page=~/$IkiWiki::config{wiki_file_regexp}/;
+               if (! defined $page || ! length $page) {
+                       $page=$feed->{dir}."/item";
+               }
+               $page=~s/\.\.//g; # avoid ".." directory tricks
+               my $c="";
+               while (exists $IkiWiki::pagesources{$page.$c} ||
+                      -e pagefile($page.$c)) {
+                       $c++
+               }
+               $guid->{page}=$page;
+               IkiWiki::debug("creating new page $page");
+       }
+       $guid->{feed}=$feed->{name};
+       
+       # To write or not to write? Need to avoid writing unchanged pages
+       # to avoid unneccessary rebuilding. The mtime from rss cannot be
+       # trusted; let's use a digest.
+       eval q{use Digest::MD5 'md5_hex'};
+       my $digest=md5_hex($params{content});
+       return unless ! exists $guid->{md5} || $guid->{md5} ne $digest;
+       $guid->{md5}=$digest;
+
+       # Create the page.
+       my $template=IkiWiki::template("aggregatepost.tmpl", blind_cache => 1);
+       my $content=$params{content};
+       $params{content}=~s/(?<!\\)\[\[/\\\[\[/g; # escape accidental wikilinks
+                                                 # and preprocessor stuff
+       $template->param(content => $params{content});
+       $template->param(url => $feed->{url});
+       $template->param(name => $feed->{name});
+       $template->param(link => $params{link}) if defined $params{link};
+       if (ref $feed->{tags}) {
+               $template->param(tags => map { tag => $_ }, @{$feed->{tags}});
+       }
+       IkiWiki::writefile($guid->{page}.".html", $IkiWiki::config{srcdir},
+               $template->output);
+
+       # Set the mtime, this lets the build process get the right creation
+       # time on record for the new page.
+       utime $mtime, $mtime, pagefile($guid->{page}) if defined $mtime;
+} #}}}
+
+sub remove_feeds () { #{{{
+       my $page=shift;
+
+       my %removed;
+       foreach my $id (keys %feeds) {
+               if ($feeds{$id}->{sourcepage} eq $page) {
+                       $feeds{$id}->{remove}=1;
+                       $removed{$id}=1;
+               }
+       }
+} #}}}
+
+sub pagefile ($) { #{{{
+       my $page=shift;
+
+       return "$IkiWiki::config{srcdir}/$page.html";
+} #}}}
+
+1
index e63bab6d76e04fed3e6b22e5fce0b7ca69ced692..1201d055c46cff36a6004bc9f6f115b3994c3a58 100644 (file)
@@ -29,7 +29,7 @@ sub import { #{{{
                call => \&change);
        IkiWiki::hook(type => "cgi", id => "skeleton", 
                call => \&cgi);
-       IkiWiki::hook(type => "cgi", id => "savestate", 
+       IkiWiki::hook(type => "savestate", id => "savestate", 
                call => \&savestate);
 } # }}}
 
index 5dbb4654c948446abb95fd5d4c7f40d35d8f06e3..1449b8931cc9ebf364d0daf7841f1d7577c358b6 100644 (file)
@@ -399,7 +399,8 @@ sub refresh () { #{{{
                my $page=pagename($file);
                
                if (! exists $oldpagemtime{$page} ||
-                   mtime(srcfile($file)) > $oldpagemtime{$page}) {
+                   mtime(srcfile($file)) > $oldpagemtime{$page} ||
+                   $forcerebuild{$page}) {
                        debug("rendering $file");
                        render($file);
                        $rendered{$file}=1;
index b1418ae34743272c583e35cdbe915026a236c258..b76c87b8e9ccf4b17c83c8e32dd88821e98016d6 100644 (file)
@@ -34,16 +34,18 @@ sub setup_standard {
                $config{wiki_file_prune_regexp}=qr/$config{wiki_file_prune_regexp}|$setup{exclude}/;
        }
 
-       debug("generating wrappers..");
-       my @wrappers=@{$setup{wrappers}};
-       delete $setup{wrappers};
-       my %startconfig=(%config);
-       foreach my $wrapper (@wrappers) {
-               %config=(%startconfig, verbose => 0, %setup, %{$wrapper});
-               checkconfig();
-               gen_wrapper();
+       if (! $config{refresh} || $config{wrappers}) {
+               debug("generating wrappers..");
+               my @wrappers=@{$setup{wrappers}};
+               delete $setup{wrappers};
+               my %startconfig=(%config);
+               foreach my $wrapper (@wrappers) {
+                       %config=(%startconfig, verbose => 0, %setup, %{$wrapper});
+                       checkconfig();
+                       gen_wrapper();
+               }
+               %config=(%startconfig);
        }
-       %config=(%startconfig);
        
        foreach my $c (keys %setup) {
                if (defined $setup{$c}) {
index 641964853ad782a911c8d871fae8ddfefd80748a..303116faae35e630a6e9239b4569849150fd3bef 100755 (executable)
@@ -18,7 +18,7 @@ extra_build:
                --plugin=brokenlinks --plugin=pagecount \
                --plugin=orphans --plugin=haiku --plugin=meta \
                --plugin=tag --plugin=polygen --plugin=pagestats \
-               --plugin=fortune
+               --plugin=fortune --plugin=aggregate
        ./mdwn2man ikiwiki 1 doc/usage.mdwn > ikiwiki.man
        ./mdwn2man ikiwiki-mass-rebuild 8 doc/ikiwiki-mass-rebuild.mdwn > ikiwiki-mass-rebuild.man
                
index babaefff2dc99a6d25a1520f42fd04125f6a60c8..6f33a3236fa2509682e2ee56b22ae41aaca85fc4 100644 (file)
@@ -1,10 +1,16 @@
 ikiwiki (1.13) UNRELEASED; urgency=low
 
+  * ikiwiki can now download and aggregate feeds with its new aggregate
+    plugin, so it's possible to implement a Planet using ikiwiki!
   * Add a run_hooks function for the common task of running all hooks of a
     given type.
   * Add a savestate hook.
   * Don't put blog post forms on pages if there's no cgiurl set.
   * Reformat front page.
+  * --setup --refresh no longer rebuilds wrappers. Use --setup --refresh
+    --wrappers to do that.
+  * Add %IkiWiki::forcerebuild to provide a way for plugins like aggregate
+    to update pages that haven't changed on disk.
 
  -- Joey Hess <joeyh@debian.org>  Sat, 29 Jul 2006 20:10:51 -0400
 
index aa8b3fa2403d42591b389d0740b674123c5ec8f2..a556fa2ed284fde3326c50614d15c4fb8dbbb8c0 100644 (file)
@@ -10,7 +10,7 @@ Package: ikiwiki
 Architecture: all
 Depends: ${perl:Depends}, libxml-simple-perl, markdown, libtimedate-perl, libhtml-template-perl, libhtml-scrubber-perl, libcgi-formbuilder-perl (>= 3.02.02), libtime-duration-perl, libcgi-session-perl, libmail-sendmail-perl, gcc | c-compiler, libc6-dev | libc-dev
 Recommends: subversion | git-core, hyperestraier
-Suggests: viewcvs, librpc-xml-perl, libtext-wikiformat-perl, polygen, tidy
+Suggests: viewcvs, librpc-xml-perl, libtext-wikiformat-perl, polygen, tidy, libxml-feed-perl, libhtml-parser-perl
 Description: a wiki compiler
  ikiwiki converts a directory full of wiki pages into html pages suitable
  for publishing on a website. Unlike many wikis, ikiwiki does not have its
index 72b457716af6434e74b45994bc4c23d42b647df6..4e2425fcb07196e91c025c0b14b3412b9e874335 100755 (executable)
@@ -10,5 +10,5 @@ if [ "$1" = configure ] && \
    dpkg --compare-versions "$2" lt "$firstcompat"; then
        ikiwiki-mass-rebuild
 else
-       ikiwiki-mass-rebuild -refresh
+       ikiwiki-mass-rebuild -refresh -wrappers
 fi
index a43cd1c9a64cc187297bd31456e883e35021c52e..0a235d7083557702ef822702485730cf3e541ad6 100644 (file)
@@ -52,6 +52,10 @@ Some of ikiwiki's features:
   Ikiwiki's own [[TODO]], [[news]], and [[plugins]] pages are good examples
   of some of the flexible ways that this can be used.
 
+  Ikiwiki can also [[plugin/aggregate]] external blogs, feeding them into
+  the wiki. This can be used to create a Planet type site that aggregates
+  interesting feeds.
+
 * [[tags]]
 
   You can tag pages and use these tags in various ways. Tags will show
index d23c88e419e3ebabb0b94870007185eb37344196..eb5b91e678532fb33f196d790968c55a7b3b3bae 100644 (file)
@@ -4,7 +4,7 @@ Ikiwiki requires [[MarkDown]] be installed, and also uses the following
 perl modules if available: `CGI::Session` `CGI::FormBuilder` (version
 3.02.02 or newer) `HTML::Template` `Mail::SendMail` `Time::Duration`
 `Date::Parse` (libtimedate-perl), `HTML::Scrubber`, `RPC::XML`,
-`XML::Simple`
+`XML::Simple`, `XML::Feed`, `HTML::Parser`
 
 If you want to install from the tarball, you should make sure that the
 required perl modules are installed, then run:
index 0596fc068cf47c5d0b5b19f9480c648553c1a0f2..1c04d09f597bba7aeab2b01207e2907365054a4a 100644 (file)
@@ -1,7 +1,7 @@
 Most of ikiwiki's [[features]] are implemented as plugins. Beyond the
 [[type/core]] features, there are plugins to [[type/format]] text,
-use [[type/tags]], show [[type/meta]] information, or just have
-[[type/fun]].
+use [[type/tags]], show [[type/meta]] information, do other [[type/useful]]
+stuff, or just have [[type/fun]].
 
 There's documentation if you want to [[write]] your own plugins, or you can
 install and use plugins contributed by others. 
diff --git a/doc/plugins/aggregate.mdwn b/doc/plugins/aggregate.mdwn
new file mode 100644 (file)
index 0000000..690904f
--- /dev/null
@@ -0,0 +1,53 @@
+This plugin allows content from other blogs to be aggregated into the wiki.
+Aggregate a blog as follows:
+
+       \[[aggregate name="example blog" feedurl="http://example.com/index.rss" url="http://example.com/" updateinterval="15" dir="example"]
+
+That example aggregates posts from the expecified RSS feed, updating no
+more frequently than once every 15 minutes, and puts a page per post under
+the example/ directory in the wiki.
+
+You can then use ikiwiki's [[blog]] support to create a blog of one or more
+aggregated feeds.
+
+## setup
+
+Make sure that you have the [[html]] plugin enabled, as the created pages are
+in html format. The [[tag]] plugin is also recommended.
+
+You will need to run ikiwiki periodically from a cron job, passing it the
+--aggregate parameter, to make it check for new posts. Here's an example
+crontab entry:
+
+       */15 * * * * ikiwiki --setup my.wiki --aggregate --refresh
+
+## usage
+
+Here are descriptions of all the supported parameters to the `aggregate`
+directive:
+
+* `name` - A name for the feed. Each feed must have a unique name.
+  Required.
+* `url` - The url to the web page for the blog that's being aggregated.
+  Required.
+* `dir` - The directory in the wiki where pages should be saved. Required.
+* `feedurl` - The url to the feed. Optional, if it's not specified ikiwiki
+  will look for feeds on the `blogurl`. RSS and atom feeds are supported.
+* `updateinterval` - How often to check for new posts, in minutes. Default
+  is 15 minutes.
+* `expireage` - Expire old items from this blog if they are older than
+  a specified number of days. Default is to never expire on age.
+* `expirecount` - Expire old items from this blog if there are more than
+  the specified number total. Oldest items will be expired first. Default
+  is to never expire on count.
+* `tag` - A tag to tag each post from the blog with. A good tag to use is
+  the name of the blog. Can be repeated multiple times. The [[tag]] plugin
+  must be enabled for this to work.
+
+Note that even if you are using subversion or another revision control
+system, pages created by aggregation will *not* be checked into revision
+control.
+
+This plugin is not enabled by default.
+
+[[tag type/useful]]
index d4a6b4efefc643a1d452bea4494b23e81505dbfd..78088aed87e0a0d36f77af68fb6bb4b489022844 100644 (file)
@@ -4,3 +4,5 @@ full text search to ikiwiki, using the [[HyperEstraier]] engine.
 It's possible to configure HyperEstraier via one of ikiwiki's
 [[templates]], but for most users, no configuration should be needed aside
 from enabling the plugin.
+
+[[tag type/useful]]
diff --git a/doc/plugins/type/useful.mdwn b/doc/plugins/type/useful.mdwn
new file mode 100644 (file)
index 0000000..92fcf5a
--- /dev/null
@@ -0,0 +1 @@
+These plugins perform various miscellaneous useful functions.
index 025a242a63c4318888225dd9975e7e680f8194f4..925717777d93360639ba3a7402dadb5944db95a5 100644 (file)
@@ -96,7 +96,7 @@ make arbitrary changes. The function is passed named parameters `page` and
 
 ## htmlize
 
-       IkiWiki::hook(type => "htmlize", id => "ext", call => \&filter);
+       IkiWiki::hook(type => "htmlize", id => "ext", call => \&htmlize);
 
 Runs on the raw source of a page and turns it into html. The id parameter
 specifies the filename extension that a file must have to be htmlized using
@@ -135,7 +135,7 @@ content.
 
 ## delete
 
-       IkiWiki::hook(type => "delete", id => "foo", call => \&dele);
+       IkiWiki::hook(type => "delete", id => "foo", call => \&delete);
 
 Each time a page or pages is removed from the wiki, the referenced function
 is called, and passed the names of the source files that were removed.
@@ -190,6 +190,8 @@ use the following hashes, using a page name as the key:
   Many plugins will need to add dependencies to this hash; the best way to do
   it is by using the IkiWiki::add_depends function, which takes as its
   parameters the page name and a [[GlobList]] of dependencies to add.
+* `%IkiWiki::forcerebuild` any pages set as the keys to this hash will be
+  treated as if they're modified and rebuilt.
 
 # A note on generating html links
 
index 10f715d9d4f30b0ab5f601da6e949b2ad2755823..e500638f4382999a65120c989c7c384a95a112af 100644 (file)
@@ -26,6 +26,8 @@ It ships with some basic templates which can be customised:
   can read the [[HyperEstraier]] docs and configure it using this.
 * `blogpost.tmpl` - Used for a form to add a post to a blog (and a rss link)
 * `rsslink.tmpl` - Used to add a rss link if blogpost.tmpl is not used.
+* `aggregatepost.tmpl` - Used by the [[plugins/aggregate]] plugin to create
+  a page for a post.
 
 If you like, you can add these to further customise it:
 
index 7d765f9e9b51d75b4e6a9b7f1cdd8735facfff72..53b3133e2c4c25389d79cbb39a4d25f057cff3c9 100644 (file)
@@ -1,24 +1 @@
-Here's a scary idea.. A plugin that can aggregate feeds from other
-locations. Presumably there would need to be a cron job to build the wiki
-periodically, and each time it's built any new items would be turned into
-pages etc. There might also need to be a way to expire old items, unless
-you wanted to keep them forever.
-
-This would allow ikiwiki to work as a kind of a planet, or at least a
-poor-man's news aggregator.
-
-* XML::Feed has a very nice interface, may require valid feeds though.
-* How to store GUIDs? Maybe as meta tags on pages, although that would need
-  caching of such metadata somewhere.
-* How to configure which feeds to pull, how often, and where to put the
-  pulled entries? One way would be command line/config file, but I think
-  better would be to use preprocessor directives in a wiki page, probably
-  the same page that inlines all the pages together.
-* Where to store when a feed was last pulled?
-
-So I need:
-
-* A way to store info from the preprocessor directives about what pages
-  to pull and expiry.
-* A way to store info on last pull time, guids, etc.
-* Switch for a mode that a) pulls b) expires old c) rebuilds wiki (for cron)
+* Still need to support feed expiry.
index 691880a96a701b3cb4b71c140735f5db79b5f5e5..a6ded5ec2186790c6f0452fb810703fb55fa0cd5 100644 (file)
@@ -24,8 +24,7 @@ These options control the mode that ikiwiki is operating in.
 * --refresh
 
   Refresh the wiki, updating any changed pages. This is the default
-  behavior so you don't normally need to specify it. If used with -setup also
-  updates any configured wrappers.
+  behavior so you don't normally need to specify it.
 
 * --rebuild
 
@@ -59,11 +58,19 @@ These options control the mode that ikiwiki is operating in.
 
   The default action when --setup is specified is to automatically generate
   wrappers for a wiki based on data in a config file, and rebuild the wiki.
-  If you also pass the --refresh option, ikiwiki will instead just refresh
-  the wiki described in the setup file.
 
   [[ikiwiki.setup]] is an example of such a config file.
 
+* --wrappers
+
+  If used with --setup --refresh, this makes it also update any configured
+  wrappers.
+
+* --aggregate
+
+  If the aggregate plugin is enabled, this makes ikiwiki poll configured
+  feeds and save new posts to the srcdir.
+
 # CONFIG OPTIONS
 
 These options configure the wiki. Note that plugins can add additional
diff --git a/ikiwiki b/ikiwiki
index 28eba6f64e98e1298e9a32e61dbe6cb1f2897847..6518b8626a943c24fa2947946c98b116d056d167 100755 (executable)
--- a/ikiwiki
+++ b/ikiwiki
@@ -22,6 +22,7 @@ sub getconfig () { #{{{
                        "verbose|v!" => \$config{verbose},
                        "rebuild!" => \$config{rebuild},
                        "refresh!" => \$config{refresh},
+                       "wrappers!" => \$config{wrappers},
                        "getctime" => \$config{getctime},
                        "wrappermode=i" => \$config{wrappermode},
                        "rcs=s" => \$config{rcs},
diff --git a/templates/aggregatepost.tmpl b/templates/aggregatepost.tmpl
new file mode 100644 (file)
index 0000000..4dfedf5
--- /dev/null
@@ -0,0 +1,13 @@
+<TMPL_VAR CONTENT>
+<hr>
+<p>
+<i>
+From <a href="<TMPL_VAR URL>"><TMPL_VAR NAME></a>
+<TMPL_IF NAME="LINK">
+; <a href="<TMPL_VAR LINK>">permalink</a>
+</TMPL_IF>
+</i>
+</p>
+<TMPL_LOOP NAME="TAGS">
+[[<TMPL_VAR TAG>]]
+</TMPL_LOOP>