From 27172572a20679701e36459339c85e0661ed2cb3 Mon Sep 17 00:00:00 2001 From: Gavin Carr Date: Mon, 15 Oct 2007 23:59:28 +0000 Subject: [PATCH] Add entries_cache_meta to general. --- general/entries_cache_meta | 440 +++++++++++++++++++++++++++++++++++++ 1 file changed, 440 insertions(+) create mode 100755 general/entries_cache_meta diff --git a/general/entries_cache_meta b/general/entries_cache_meta new file mode 100755 index 0000000..0a112b1 --- /dev/null +++ b/general/entries_cache_meta @@ -0,0 +1,440 @@ +# vim: ft=perl +# Blosxom Plugin: entries_cache_meta +# Author(s): Jason Thaxter +# Version: 0.6 + +package entries_cache_meta; + +# --- Configurable variables ----- + +# +# Caching variables +# + +# How many minutes delay before entries are re-indexed? +# (In minutes) +# default: 15 +# zero means never auto-reindex +$cache_period; + +# reindex password via query string to force re-indexing +# default: none (re-index by time only) +$reindex_passwd; + +# if true, this will warn when the cachefile can't be locked +# default: off +$write_lock_warn; + +# +# Meta-related variables +# + +# What prefix should I expect prepended to each meta tag? +# default: meta- +$meta_prefix; + +# If set, this meta variable will enable you to set modification times +# e.g.: +# meta-last_modified: 2003/01/12 10:33:33 +# see pod docs re: time format +# default: mtime +$meta_mtime; + +# enabled +# default: 1 +# set to zero to disable this plugin +# good for use w/ config plugin +$enabled; + +# -------------------------------- + +# defaults +$cache_period = 15 if not defined $cache_period; +$meta_prefix ||= 'meta-'; +$meta_mtime = 'mtime' unless defined $meta_mtime; +$enabled = 1 unless defined $enabled; + +# standard perl modules +use Fcntl qw(:DEFAULT :flock); +use File::stat; +use File::Find; +use Data::Dumper; + +# standard for blosxom +use CGI qw/:standard/; + +# we'll use Date::Parse if we have it +$have_date_parse; +eval { require Date::Parse; }; +if ($@) { + use Time::Local; +} +else { + $have_date_parse = 1; +} + +%cache; # the cache +%indexes = (); # nothing - we don't do static +$reindex; # reindex or not +*CACHE; # for the cache file +$reindexed; # flag for "save cache" + +# the filename where the cache is stored +$cachefile = "$blosxom::plugin_state_dir/entries_cache_meta"; +# and a temporary one while generating the cache +$cache_tmp = "$cachefile.TMP"; + +sub start { + + return 0 if ( not $enabled or param('-all') ); + + # Read cache and reindex if failed or otherwise directed + ( + ( + not( $reindex_passwd and param('reindex') eq $reindex_passwd ) + and not( $cache_period + and -f "$cachefile" + and stat($cachefile)->mtime lt( time() - $cache_period * 60 ) ) + ) + and ( open( MYCACHE, $cachefile ) + and $index = join '', + and $index =~ /\$VAR1 = / + and eval($index) + and !$@ + and %cache = %$VAR1 + and close MYCACHE ) + + ) + or $reindex = &lokkit( \*CACHE ); + + return 1; +} + +sub entries { + + # If we haven't flagged a need to re-index, + # copy from the cache + return sub { + my %files; + foreach ( keys %cache ) { + + # copy into cache if the file exists + $files{$_} = $cache{$_}{mtime} if -f $_; + } + return ( \%files, \%indexes ); + } + unless $reindex; + + # otherwise, do a full reindex + return sub { + + # Check to see if previously indexed files exist, and then rescan + # the datadir for any new files, while preserving the old times + + for my $file ( keys %cache ) { + -f $file or do { $reindexed++; delete $cache{$file} }; + } + + find( + sub { + + # easier to read. + $ffname = $File::Find::name; + + # return if we're out of our depth + my $curr_depth = $File::Find::dir =~ tr[/][]; + if ( $blosxom::depth and $curr_depth > $blosxom::depth ) { + $cache{$ffname} + and delete $cache{$ffname}; + return; + } + + # only bother for real entries + return + unless ( $ffname =~ +m!^$blosxom::datadir/(?:(.*)/)?(.+)\.$blosxom::file_extension$! + and $2 ne 'index' + and $2 !~ /^\./ + and ( -r "$ffname" ) + and ++$reindexed ); + + # process meta tags + if ( -T "$ffname" and open( FF, "<$ffname" ) ) { + $meta_title = ; + chomp($meta_title); + $cache{$ffname}{title} = $meta_title; + while () { + + # get values + my ( $key, $value ) = m/^$meta_prefix(\w+)\s*:\s*(.+)$/; + last if not $key; + + # set values + if ( $key ne "$meta_mtime" ) { + $cache{$ffname}{$key} = $value; + } + + # set modification time + # with a double negative (hey) + else { + if ($have_date_parse) { + $time = Date::Parse::str2time($value); + } + elsif ( + my ( $yr, $mo, $day, $hr, $min, $sec, $tz ) = ( + $value =~ +m! (\d{4}) [/\:\-] (\d{2}) [/\:\-] (\d{2}) \s+ + (\d{2}) : (\d{2}) : (\d{2}) + \s*((UTC|GMT)*)!x + ) + ) + { + if ($tz) { + $time = + timegm( $sec, $min, $hr, $day, --$mo, + $yr ); + } + else { + $time = + timelocal( $sec, $min, $hr, $day, --$mo, + $yr ); + } + } + else { + warn "unparseable time in $ffname: $value"; + } + $cache{$ffname}{mtime} = $time; + } + } + close FF; + } + else { + warn "couldn't open entry ($ffname): $!"; + } + + # If we have no meta mtime and no cached time, + # stat the file and store it. + if ( $cache{$ffname}{mtime} ) { + $files{$ffname} = $cache{$ffname}{mtime}; + } + else { # make sure blosxom behaves normally + $files{$ffname} = stat($ffname)->mtime; + $cache{$ffname}{mtime} = $files{$ffname}; + } + + # show or not to show future entries + if ( not $blosxom::show_future_entries + and $files{$ffname} > time() ) + { + delete $files{$ffname} and return; + } + + }, + $blosxom::datadir + ); + + return ( \%files, \%indexes ); # indexes is bogus: we don't do static + } +} + +# put the stuff into $meta:: namespace for story rendering +# and trim meta tags out of our story +sub story { + my ( $pkg, $path, $filename, $story_ref, $title_ref, $body_ref ) = @_; + + # first, load up our cached meta values + foreach my $key ( keys %{ $cache{$filename} } ) { + ${"meta::$key"} = $cache{$filename}{$key}; + } + + # next, remove any meta tags from the body + my ( $body, $in_body ); + foreach ( split /\n/, $$body_ref ) { + if ($in_body) { + $body .= "$_\n"; + } + elsif (/^$meta_prefix(\w+)\s*:\s*(.+)$/) { + ; + } + else { + $in_body = 1; + $body .= "$_\n"; + } + } + + $$body_ref = $body; + + return 1; +} + +# save cache - as late as possible +# this gives other plugins a chance to alter values +# or, forbid us from caching them! +sub end { + &stuffit( \*CACHE, Dumper \%cache ) if ($reindexed); + 1; +} + +##################################################################### +# Internal subs +# + +# Reserve file for writing +sub lokkit { + local *FH = shift; + + # open it + my $umask = umask 002; # group-write is useful + sysopen( FH, "$cache_tmp", O_RDWR | O_CREAT ) + or ( warn "can't open file $cache_tmp: $!" and return ); + umask $umask; # restore so it doesn't affect other plugins + + # lock file + flock( FH, LOCK_EX | LOCK_NB ) + or ( close FH + and ( not $write_lock_warn or warn "can't lock file: $!" ) + and return ); + + return 1; +} + +# Write and release file +sub stuffit { + local *FH = shift; + local $contents = shift; + + my $err; + print FH $contents or $err = "can't write cache $cache_tmp: $!"; + flock( FH, LOCK_UN ) or $err = "can't unlock cache $cache_tmp: $!"; + close FH or $err = "can't close cache $cache_tmp: $!"; + + if ( not $err ) { + rename "$cache_tmp", $cachefile + or warn "Error installing cache $cache_tmp: $!"; + } + else { + warn $err; + unlink "$cache_tmp"; + } +} + +1; + +__END__ + +=head1 NAME - entries_cache_meta + +Blosxom Plug-in: entries_cache_meta + +=head1 DESCRIPTION + +The entries_cache_meta plugin is Yet Another Caching Plugin, with some +additional features, notably meta-tagging. + +By combining the meta-tag functionality with the entries cache, it becomes +possible to write or use plugins that access meta-values outside the C +hook. For example, you could use this plugin to write another one showing the +most recent entry for each author defined in meta tags. + +Additionally, it makes use of file locking to avoid from re-indexing if another +request already has re-indexing in progress. Simultaneous re-indexing could +corrupt the cache file, or bog down the server with redundant, expensive tasks; +the larger and busier the site, the more likely these problems. For added +security, you must supply a password if you want to force re-indexing via query +string; this prevents any Blosxom-savvy user from forcing a re-index on your +site. + +=head1 USAGE + +A properly permissioned $plugin_state_dir is required. Configuration is +optional, but there are a few useful configuration variables. + +=over 4 + +=item $cache_period + +How often, in minutes, to reindex automatically. If set to zero, re-indexing will never +be automatic. + +=item $reindex_passwd + +What query string password forces reindex. You can force a scan by appending a +query string, e.g. C to the end of the url. This will +also cause meta tags to be updated. However, for security's sake, you must +set the password in the configuration to use this. + +=item $write_lock_warn + +Send a warning to the error log when it can't get a write-lock on the cache +file. This is mostly useful for verifying that write-locking actually does +something. + +=item $meta_prefix + +What prefix marks meta variable names. Defaults to C. An empty string +should be permitted, but currently it isn't. + +=item $meta_mtime + +The name of the meta-property for file modification times. If this property is +present in a given entry, it will override the modification time of the file as +the entry's time. The default value is "mtime". + +The format of the time is obviously important: it can be either + + meta-mtime: YYYY/MM/DD HH:MM:SS [UTC|GMT] + +or, if Date::Parse is present, any format parseable by that module. Either way, +unparseable dates are simply ignored as if the property was not present. This +feature may be disabled by setting it to an empty string. + +=back + +=head1 VERSION + +Version 0.6 + +=head1 AUTHOR + +Jason Thaxter + +This plugin is now maintained by the Blosxom Sourceforge Team, +. + +=head1 SEE ALSO + +Blosxom Home/Docs/Licensing: http://blosxom.sourceforge.net + +Blosxom Plugin Docs: http://blosxom.sourceforge.net/documentation/users/plugins.html + +=head1 BUGS + +It doesn't currently work in static mode, in part because the premise of static +mode is to be a performance benefit all on its own. Also because I don't use +static mode and I'm lazy. + +Please send bug reports and feedback to the Blosxom development mailing list +. + +=head1 LICENSE + +entries_cache_meta plugin +Copyright 2004, Jason Thaxter + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the "Software"), +to deal in the Software without restriction, including without limitation +the rights to use, copy, modify, merge, publish, distribute, sublicense, +and/or sell copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR +OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. -- 2.30.2