2 # Blosxom Plugin: entries_cache_meta
3 # Author(s): Jason Thaxter <sseye@ahab.com>
6 package entries_cache_meta;
8 # --- Configurable variables -----
14 # How many minutes delay before entries are re-indexed?
17 # zero means never auto-reindex
20 # reindex password via query string to force re-indexing
21 # default: none (re-index by time only)
24 # if true, this will warn when the cachefile can't be locked
29 # Meta-related variables
32 # What prefix should I expect prepended to each meta tag?
36 # If set, this meta variable will enable you to set modification times
38 # meta-last_modified: 2003/01/12 10:33:33
39 # see pod docs re: time format
45 # set to zero to disable this plugin
46 # good for use w/ config plugin
49 # --------------------------------
52 $cache_period = 15 if not defined $cache_period;
53 $meta_prefix ||= 'meta-';
54 $meta_mtime = 'mtime' unless defined $meta_mtime;
55 $enabled = 1 unless defined $enabled;
57 # standard perl modules
58 use Fcntl qw(:DEFAULT :flock);
63 # standard for blosxom
64 use CGI qw/:standard/;
66 # we'll use Date::Parse if we have it
68 eval { require Date::Parse; };
77 %indexes = (); # nothing - we don't do static
78 $reindex; # reindex or not
79 *CACHE; # for the cache file
80 $reindexed; # flag for "save cache"
82 # the filename where the cache is stored
83 $cachefile = "$blosxom::plugin_state_dir/entries_cache_meta";
84 # and a temporary one while generating the cache
85 $cache_tmp = "$cachefile.TMP";
89 return 0 if ( not $enabled or param('-all') );
91 # Read cache and reindex if failed or otherwise directed
94 not( $reindex_passwd and param('reindex') eq $reindex_passwd )
95 and not( $cache_period
97 and stat($cachefile)->mtime lt( time() - $cache_period * 60 ) )
99 and ( open( MYCACHE, $cachefile )
100 and $index = join '', <MYCACHE>
101 and $index =~ /\$VAR1 = /
108 or $reindex = &lokkit( \*CACHE );
115 # If we haven't flagged a need to re-index,
116 # copy from the cache
119 foreach ( keys %cache ) {
121 # copy into cache if the file exists
122 $files{$_} = $cache{$_}{mtime} if -f $_;
124 return ( \%files, \%indexes );
128 # otherwise, do a full reindex
131 # Check to see if previously indexed files exist, and then rescan
132 # the datadir for any new files, while preserving the old times
134 for my $file ( keys %cache ) {
135 -f $file or do { $reindexed++; delete $cache{$file} };
142 $ffname = $File::Find::name;
144 # return if we're out of our depth
145 my $curr_depth = $File::Find::dir =~ tr[/][];
146 if ( $blosxom::depth and $curr_depth > $blosxom::depth ) {
148 and delete $cache{$ffname};
152 # only bother for real entries
155 m!^$blosxom::datadir/(?:(.*)/)?(.+)\.$blosxom::file_extension$!
162 if ( -T "$ffname" and open( FF, "<$ffname" ) ) {
165 $cache{$ffname}{title} = $meta_title;
169 my ( $key, $value ) = m/^$meta_prefix(\w+)\s*:\s*(.+)$/;
173 if ( $key ne "$meta_mtime" ) {
174 $cache{$ffname}{$key} = $value;
177 # set modification time
178 # with a double negative (hey)
180 if ($have_date_parse) {
181 $time = Date::Parse::str2time($value);
184 my ( $yr, $mo, $day, $hr, $min, $sec, $tz ) = (
186 m! (\d{4}) [/\:\-] (\d{2}) [/\:\-] (\d{2}) \s+
187 (\d{2}) : (\d{2}) : (\d{2})
194 timegm( $sec, $min, $hr, $day, --$mo,
199 timelocal( $sec, $min, $hr, $day, --$mo,
204 warn "unparseable time in $ffname: $value";
206 $cache{$ffname}{mtime} = $time;
212 warn "couldn't open entry ($ffname): $!";
215 # If we have no meta mtime and no cached time,
216 # stat the file and store it.
217 if ( $cache{$ffname}{mtime} ) {
218 $files{$ffname} = $cache{$ffname}{mtime};
220 else { # make sure blosxom behaves normally
221 $files{$ffname} = stat($ffname)->mtime;
222 $cache{$ffname}{mtime} = $files{$ffname};
225 # show or not to show future entries
226 if ( not $blosxom::show_future_entries
227 and $files{$ffname} > time() )
229 delete $files{$ffname} and return;
236 return ( \%files, \%indexes ); # indexes is bogus: we don't do static
240 # put the stuff into $meta:: namespace for story rendering
241 # and trim meta tags out of our story
243 my ( $pkg, $path, $filename, $story_ref, $title_ref, $body_ref ) = @_;
245 # first, load up our cached meta values
246 foreach my $key ( keys %{ $cache{$filename} } ) {
247 ${"meta::$key"} = $cache{$filename}{$key};
250 # next, remove any meta tags from the body
251 my ( $body, $in_body );
252 foreach ( split /\n/, $$body_ref ) {
256 elsif (/^$meta_prefix(\w+)\s*:\s*(.+)$/) {
270 # save cache - as late as possible
271 # this gives other plugins a chance to alter values
272 # or, forbid us from caching them!
274 &stuffit( \*CACHE, Dumper \%cache ) if ($reindexed);
278 #####################################################################
282 # Reserve file for writing
287 my $umask = umask 002; # group-write is useful
288 sysopen( FH, "$cache_tmp", O_RDWR | O_CREAT )
289 or ( warn "can't open file $cache_tmp: $!" and return );
290 umask $umask; # restore so it doesn't affect other plugins
293 flock( FH, LOCK_EX | LOCK_NB )
295 and ( not $write_lock_warn or warn "can't lock file: $!" )
301 # Write and release file
304 local $contents = shift;
307 print FH $contents or $err = "can't write cache $cache_tmp: $!";
308 flock( FH, LOCK_UN ) or $err = "can't unlock cache $cache_tmp: $!";
309 close FH or $err = "can't close cache $cache_tmp: $!";
312 rename "$cache_tmp", $cachefile
313 or warn "Error installing cache $cache_tmp: $!";
325 =head1 NAME - entries_cache_meta
327 Blosxom Plug-in: entries_cache_meta
331 The entries_cache_meta plugin is Yet Another Caching Plugin, with some
332 additional features, notably meta-tagging.
334 By combining the meta-tag functionality with the entries cache, it becomes
335 possible to write or use plugins that access meta-values outside the C<story>
336 hook. For example, you could use this plugin to write another one showing the
337 most recent entry for each author defined in meta tags.
339 Additionally, it makes use of file locking to avoid from re-indexing if another
340 request already has re-indexing in progress. Simultaneous re-indexing could
341 corrupt the cache file, or bog down the server with redundant, expensive tasks;
342 the larger and busier the site, the more likely these problems. For added
343 security, you must supply a password if you want to force re-indexing via query
344 string; this prevents any Blosxom-savvy user from forcing a re-index on your
349 A properly permissioned $plugin_state_dir is required. Configuration is
350 optional, but there are a few useful configuration variables.
356 How often, in minutes, to reindex automatically. If set to zero, re-indexing will never
359 =item $reindex_passwd
361 What query string password forces reindex. You can force a scan by appending a
362 query string, e.g. C<?reindex=mypassword> to the end of the url. This will
363 also cause meta tags to be updated. However, for security's sake, you must
364 set the password in the configuration to use this.
366 =item $write_lock_warn
368 Send a warning to the error log when it can't get a write-lock on the cache
369 file. This is mostly useful for verifying that write-locking actually does
374 What prefix marks meta variable names. Defaults to C<meta->. An empty string
375 should be permitted, but currently it isn't.
379 The name of the meta-property for file modification times. If this property is
380 present in a given entry, it will override the modification time of the file as
381 the entry's time. The default value is "mtime".
383 The format of the time is obviously important: it can be either
385 meta-mtime: YYYY/MM/DD HH:MM:SS [UTC|GMT]
387 or, if Date::Parse is present, any format parseable by that module. Either way,
388 unparseable dates are simply ignored as if the property was not present. This
389 feature may be disabled by setting it to an empty string.
399 Jason Thaxter <sseye@ahab.com>
401 This plugin is now maintained by the Blosxom Sourceforge Team,
402 <blosxom-devel@lists.sourceforge.net>.
406 Blosxom Home/Docs/Licensing: http://blosxom.sourceforge.net
408 Blosxom Plugin Docs: http://blosxom.sourceforge.net/documentation/users/plugins.html
412 It doesn't currently work in static mode, in part because the premise of static
413 mode is to be a performance benefit all on its own. Also because I don't use
414 static mode and I'm lazy.
416 Please send bug reports and feedback to the Blosxom development mailing list
417 <blosxom-devel@lists.sourceforge.net>.
421 entries_cache_meta plugin
422 Copyright 2004, Jason Thaxter
424 Permission is hereby granted, free of charge, to any person obtaining a
425 copy of this software and associated documentation files (the "Software"),
426 to deal in the Software without restriction, including without limitation
427 the rights to use, copy, modify, merge, publish, distribute, sublicense,
428 and/or sell copies of the Software, and to permit persons to whom the
429 Software is furnished to do so, subject to the following conditions:
431 The above copyright notice and this permission notice shall be included
432 in all copies or substantial portions of the Software.
434 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
435 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
436 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
437 THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
438 OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
439 ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
440 OTHER DEALINGS IN THE SOFTWARE.