|
From: <ik...@us...> - 2009-09-05 09:35:44
|
Revision: 46
http://webfetch.svn.sourceforge.net/webfetch/?rev=46&view=rev
Author: ikluft
Date: 2009-09-05 09:35:33 +0000 (Sat, 05 Sep 2009)
Log Message:
-----------
new module WebFetch::Output::TWiki
Added Paths:
-----------
branches/v0.13/lib/WebFetch/Output/TWiki.pm
Added: branches/v0.13/lib/WebFetch/Output/TWiki.pm
===================================================================
--- branches/v0.13/lib/WebFetch/Output/TWiki.pm (rev 0)
+++ branches/v0.13/lib/WebFetch/Output/TWiki.pm 2009-09-05 09:35:33 UTC (rev 46)
@@ -0,0 +1,414 @@
+#
+# WebFetch::Output::TWiki - save data into a TWiki web site
+#
+# Copyright (c) 2009 Ian Kluft. This program is free software; you can
+# redistribute it and/or modify it under the terms of the GNU General Public
+# License Version 3. See http://www.webfetch.org/GPLv3.txt
+
+package WebFetch::Output::TWiki;
+
+use warnings;
+use strict;
+use WebFetch;
+use base "WebFetch";
+use DB_File;
+
+# define exceptions/errors
+use Exception::Class (
+ "WebFetch::Output::TWiki::Exception::NoRoot" => {
+ isa => "WebFetch::Exception",
+ alias => "throw_twiki_no_root",
+ description => "WebFetch::Output::TWiki needs to be provided "
+ ."a twiki_root parameter",
+ },
+ "WebFetch::Output::TWiki::Exception::NotFound" => {
+ isa => "WebFetch::Exception",
+ alias => "throw_twiki_not_found",
+ description => "the directory in the twiki_root parameter "
+ ."doesn't exist or doesn't have a lib subdirectory",
+ },
+ "WebFetch::Output::TWiki::Exception::Require" => {
+ isa => "WebFetch::Exception",
+ alias => "throw_twiki_require",
+ description => "failed to import TWiki or TWiki::Func modules",
+ },
+ "WebFetch::Output::TWiki::Exception::NoConfig" => {
+ isa => "WebFetch::Exception",
+ alias => "throw_twiki_no_config",
+ description => "WebFetch::Output::TWiki needs to be provided "
+ ."a config_topic parameter",
+ },
+ "WebFetch::Output::TWiki::Exception::ConfigMissing" => {
+ isa => "WebFetch::Exception",
+ alias => "throw_twiki_config_missing",
+ description => "WebFetch::Output::TWiki is missing a required "
+ ."configuration parameter",
+ },
+ "WebFetch::Output::TWiki::Exception::Oops" => {
+ isa => "WebFetch::Exception",
+ alias => "throw_twiki_oops",
+ description => "WebFetch::Output::TWiki returned errors from "
+ ."saving one or more entries",
+ },
+);
+
+=head1 NAME
+
+WebFetch::Output::TWiki - The great new WebFetch::Output::TWiki!
+
+=head1 VERSION
+
+Version 0.01
+
+=cut
+
+# globals/defaults
+our @Options = ( "twiki_root=s", "config_topic=s", "config_key=s" );
+our $Usage = "--twiki_root path-to-twiki --config_topic web.topic "
+ ."--config_key keyword";
+our @default_field_names = ( qw( key web parent prefix template form
+ options ));
+
+# no user-servicable parts beyond this point
+
+our $VERSION = '0.01';
+
+# register capabilities with WebFetch
+__PACKAGE__->module_register( "cmdline", "output:twiki" );
+
+=head1 SYNOPSIS
+
+Quick summary of what the module does.
+
+Perhaps a little code snippet.
+
+ use WebFetch::Output::TWiki;
+
+ my $foo = WebFetch::Output::TWiki->new();
+ ...
+
+=head1 EXPORT
+
+A list of functions that can be exported. You can delete this section
+if you don't export anything, such as for a purely object-oriented module.
+
+=head1 FUNCTIONS
+
+=head2 get_twiki_config
+
+=cut
+
+# read the TWiki configuation
+sub get_twiki_config
+{
+ my $self = shift;
+ WebFetch::debug "in get_twiki_config";
+
+ # find the TWiki modules
+ if ( ! exists $self->{twiki_root}) {
+ throw_twiki_no_root( "TWiki root directory not defined" );
+ }
+ if (( ! -d $self->{twiki_root}) or ( ! -d $self->{twiki_root}."/lib" ))
+ {
+ throw_twiki_not_found( "can't find TWiki root or lib at "
+ .$self->{twiki_root});
+ }
+
+ # load the TWiki modules
+ WebFetch::debug "loading TWiki modules";
+ push @INC, $self->{twiki_root}."/lib";
+ eval { require TWiki; require TWiki::Func; };
+ if ( $@ ) {
+ throw_twiki_require ( $@ );
+ }
+
+ # initiate TWiki library, create session as user "WebFetch"
+ $self->{twiki_obj} = TWiki->new( "WebFetch" );
+
+ # get the contents of the TWiki topic which contains our configuration
+ if ( !exists $self->{config_topic}) {
+ throw_twiki_no_config( "TWiki configuration page for WebFetch "
+ ."not defined" );
+ }
+ my ( $web, $topic ) = split /\./, $self->{config_topic};
+ WebFetch::debug "config_topic: ".$self->{config_topic}
+ ." -> $web, $topic";
+ if (( ! defined $web ) or ( ! defined $topic )) {
+ throw_twiki_no_config( "TWiki configuration page for WebFetch "
+ ."must be defined in the format web.topic" );
+ }
+
+ # check if a config_key was specified before we read the configuration
+ if ( !exists $self->{config_key}) {
+ throw_twiki_no_config( "TWiki configuration key for WebFetch "
+ ."not defined" );
+ }
+
+ # read the configuration info
+ my $config = TWiki::Func::readTopic( $web, $topic );
+
+ # if STARTINCLUDE and STOPINCLUDE are present, use only what's between
+ if ( $config =~ /%STARTINCLUDE%\s*(.*)\s*%STOPINCLUDE%/s ) {
+ $config = $1;
+ }
+
+ # parse the configuration
+ WebFetch::debug "parsing configuration";
+ my ( @fnames, $line );
+ $self->{twiki_config_all} = [];
+ $self->{twiki_keys} = {};
+ foreach $line ( split /\r*\n+/s, $config ) {
+ if ( $line =~ /^\|\s*(.*)\s*\|\s*$/ ) {
+ my @entries = split /\s*\|\s*/, $1;
+
+ # check first line for field headings
+ if ( ! @{$self->{twiki_config_all}}) {
+ if ( $entries[0] =~ /\*\w+\*/ ) {
+ # save table headings as field names
+ my $field;
+ foreach $field ( @entries ) {
+ if ( $field =~ /\*(\w*)\*/ )
+ {
+ push @fnames, lc($1);
+ } else {
+ my $tmp = lc($field);
+ $tmp =~ s/\W//g;
+ push @fnames, $tmp;
+ }
+ }
+ next;
+ } else {
+ # use default field names
+ @fnames = @default_field_names;
+ }
+ }
+ WebFetch::debug "field names: ".join " ", @fnames;
+
+ # save the entries
+ # it isn't a heading row if we got here
+ # transfer array @entries to named fields in %config
+ WebFetch::debug "data row: ".join " ", @entries;
+ my ( $i, $key, %config );
+ for ( $i=0; $i < scalar @fnames; $i++ ) {
+ $config{ $fnames[$i]} = $entries[$i];
+ if ( $fnames[$i] eq "key" ) {
+ $key = $entries[$i];
+ }
+ }
+
+ # save the %config row in @{$self->{twiki_config_all}}
+ if (( defined $key )
+ and ( !exists $self->{twiki_keys}{$key}))
+ {
+ push @{$self->{twiki_config_all}}, \%config;
+ $self->{twiki_keys}{$key} = ( scalar
+ @{$self->{twiki_config_all}}) - 1;
+ }
+ }
+ }
+
+ # select the line which is for this request
+ if ( ! exists $self->{twiki_keys}{$self->{config_key}}) {
+ throw_twiki_no_config "no configuration found for key "
+ .$self->{config_key};
+ }
+ $self->{twiki_config} = $self->{twiki_config_all}[$self->{twiki_keys}{$self->{config_key}}];
+ WebFetch::debug "twiki_config: ".join( " ", %{$self->{twiki_config}});
+}
+
+=head2 write_to_twiki
+
+=cut
+
+sub write_to_twiki
+{
+ my $self = shift;
+ my ( $config, $name );
+
+ # get config variables
+ $config = $self->{twiki_config};
+ foreach $name ( qw( key web parent prefix template form )) {
+ if ( !exists $self->{twiki_config}{$name}) {
+ throw_twiki_config_missing( "missing config parameter "
+ .$name );
+ }
+ }
+
+ # get text of template topic
+ my $template = TWiki::Func::readTopic( $config->{web},
+ $config->{template});
+
+ # determine unique identifier field
+ my $id_field = $self->wk2fnum( "id" );
+ if ( ! defined $id_field ) {
+ $id_field = $self->wk2fnum( "url" );
+ } elsif ( ! defined $id_field ) {
+ $id_field = $self->wk2fnum( "title" );
+ }
+ WebFetch::debug "write_to_twiki: id_field=$id_field";
+
+ # open DB file for tracking unique IDs of articles already processed
+ my %id_index;
+ tie %id_index, 'DB_File',
+ $self->{dir}."/".$config->{key}."_id_index.db",
+ &DB_File::O_CREAT|&DB_File::O_RDWR, 0640;
+
+ # determine initial topic name
+ my ( %topics, @topics );
+ @topics = TWiki::Func::getTopicList( $config->{web});
+ foreach ( @topics ) {
+ $topics{$_} = 1;
+ }
+ my $tnum_counter = 0;
+ my $tnum_format = $config->{prefix}."-%07d";
+
+ # create topics with metadata from each WebFetch data record
+ my $entry;
+ my @oopses;
+ foreach $entry ( @{$self->{data}{records}}) {
+
+ # check that this entry hasn't already been forwarded to TWiki
+ if ( exists $id_index{$entry->[$id_field]}) {
+ next;
+ }
+ $id_index{$entry->[$id_field]} = time;
+
+ # select topic name
+ my $topicname = sprintf $tnum_format, $tnum_counter;
+ while ( exists $topics{$topicname}) {
+ $tnum_counter++;
+ $topicname = sprintf $tnum_format, $tnum_counter;
+ }
+ $tnum_counter++;
+ $topics{$topicname} = 1;
+ my $text = $template;
+ WebFetch::debug "write_to_twiki: writing $topicname";
+
+ # create topic metadata
+ my $meta = TWiki::Meta->new ( $self->{twiki_obj},
+ $config->{web}, $topicname );
+ $meta->put( "TOPICPARENT",
+ { name => $config->{parent}});
+ $meta->put( "FORM", { name => $config->{form}});
+ my $fnum;
+ for ( $fnum = 0; $fnum <= @{$self->{data}{fields}}; $fnum++ ) {
+ WebFetch::debug "meta: ".$self->{data}{fields}[$fnum]
+ ." = ".$entry->[$fnum];
+ ( defined $self->{data}{fields}[$fnum]) or next;
+ ( $self->{data}{fields}[$fnum] eq "xml") and next;
+ ( defined $entry->[$fnum]) or next;
+ WebFetch::debug "meta: OK";
+ $meta->putKeyed( "FIELD", {
+ name => $self->{data}{fields}[$fnum],
+ value => $entry->[$fnum] });
+ }
+
+ # save a special title field for TWiki indexes
+ my $index_title = $entry->[$self->wk2fnum( "title" )];
+ $index_title =~ s/[\t\r\n\|]+/ /gs;
+ $index_title =~ s/^\s*//;
+ $index_title =~ s/\s*$//;
+ if ( length($index_title) > 60 ) {
+ substr( $index_title, 56 ) = "...";
+ }
+ WebFetch::debug "title: $index_title";
+ $meta->putKeyed( "FIELD", {
+ name => "IndexTitle",
+ title => "Indexing title",
+ value => $index_title });
+
+ # save the topic
+ my $oopsurl = TWiki::Func::saveTopic( $config->{web},
+ $topicname, $meta, $text );
+ if ( $oopsurl ) {
+ WebFetch::debug "write_to_twiki: $topicname - $oopsurl";
+ push @oopses, $entry->[$self->wk2fnum( "title" ) or 0]
+ ." -> ".$topicname." ".$oopsurl;
+ }
+ }
+
+ # check for errors
+ if ( @oopses ) {
+ throw_twiki_oops( "These saves failed:\n".join "\n", @oopses );
+ }
+}
+
+=head2 fmt_handler_twiki
+
+=cut
+
+# TWiki format handler
+sub fmt_handler_twiki
+{
+ my $self = shift;
+ my $filename = shift;
+
+ # get configuration from TWiki
+ $self->get_twiki_config;
+
+ # write to TWiki topic
+ $self->write_to_twiki;
+
+ # no savables for WebFetch::save - mark it OK
+ $self->no_savables_ok;
+ 1;
+}
+
+
+=head1 AUTHOR
+
+Ian Kluft, C<< <ikluft at cpan.org> >>
+
+=head1 BUGS
+
+Please report any bugs or feature requests to C<bug-webfetch-output-twiki at rt.cpan.org>, or through
+the web interface at L<http://rt.cpan.org/NoAuth/ReportBug.html?Queue=WebFetch-Output-TWiki>. I will be notified, and then you'll
+automatically be notified of progress on your bug as I make changes.
+
+
+
+
+=head1 SUPPORT
+
+You can find documentation for this module with the perldoc command.
+
+ perldoc WebFetch::Output::TWiki
+
+
+You can also look for information at:
+
+=over 4
+
+=item * RT: CPAN's request tracker
+
+L<http://rt.cpan.org/NoAuth/Bugs.html?Dist=WebFetch-Output-TWiki>
+
+=item * AnnoCPAN: Annotated CPAN documentation
+
+L<http://annocpan.org/dist/WebFetch-Output-TWiki>
+
+=item * CPAN Ratings
+
+L<http://cpanratings.perl.org/d/WebFetch-Output-TWiki>
+
+=item * Search CPAN
+
+L<http://search.cpan.org/dist/WebFetch-Output-TWiki/>
+
+=back
+
+
+=head1 ACKNOWLEDGEMENTS
+
+
+=head1 COPYRIGHT & LICENSE
+
+Copyright 2009 Ian Kluft, all rights reserved.
+
+This program is free software; you can redistribute it and/or modify it
+under the same terms as Perl itself.
+
+
+=cut
+
+1; # End of WebFetch::Output::TWiki
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|