#!/usr/bin/perl # # FOLLOWME -- Update a set of html files from a template file use strict; use lib "../lib"; use Getopt::Std; use File::Find; use FileHandle; use HtmlBlocks; #---------------------------------------------------------------------- # Configuration use constant DEFAULT_TEMPLATE => 'template.htm'; use constant DEFAULT_HTML_EXTENSION => '.html'; use constant DEFAULT_DIRECTORY => '.'; #---------------------------------------------------------------------- # Main routine my %opt; getopts ("mt:x:", \%opt) || die "Unrecognized command line switches\n"; # Parse template file name into directory, base, and extension # Read the template my $template_file = $opt{t} || DEFAULT_TEMPLATE; my $template = slurp ($template_file); exit unless length ($template); my $template_html = HtmlBlocks::extract ($template); # Subroutine that modifies every html file my $ext = quotemeta ($opt{x} || DEFAULT_HTML_EXTENSION); my $editor = sub { my $content_file = $_; # Don't modify file in directories starting with . my @dir = split (/\//, $File::Find::dir); return if $dir[-1] =~ /^\../; return if $content_file !~ /$ext$/o or $content_file eq $template; # Extract html blocks from content file my $content = slurp ($content_file); return unless length ($content); my $html = eval {HtmlBlocks::extract ($content)}; if ($@) { warn "$content_file: $@"; return; } # Check for entries in the content file that aren't in the template my @missing; foreach (keys %$html) { push (@missing, $_) unless exists $template_html->{$_}; } if (@missing && ! $opt{m}) { warn "$content_file: Extra blocks in file $content_file: " . join (',', @missing) . "\n"; return; } # Substitute them into template my $output = eval {HtmlBlocks::substitute ($template, $html)}; if ($@) { warn "$template_file: $@"; return; } my $out = FileHandle->new (">$content_file"); unless ($out) { warn "Can't write to $content_file: $!\n"; return; } print $out $output; $out->close; }; # Edit all html files passed on command line. If the file is a directory. # edit html files in thet directory and subdirectories below it push (@ARGV, DEFAULT_DIRECTORY) unless @ARGV; foreach (@ARGV) { if (-d $_) { find ($editor, $_); } else { &$editor; } } #---------------------------------------------------------------------- # Read a file into a string sub slurp { my ($file) = @_; local $/; my $in = FileHandle->new ($file); unless ($in) { warn "Couldn't read $file: $!\n"; return ''; } my $input = <$in>; $in->close; return $input; } __END__ =pod =head1 NAME Followme is an HTML templating program =head1 SYNOPSIS followme [-x html_extension] [-t template_file ] -m [file ...] =head1 DESCRIPTION Followme is an html template processor. It produces a new html file from a template and an old html file. The purpose if this script is to keep html files in synch with a template. One changes the template and then runs this script to propogate the changes in the template to the other html files. Followme works by combining text from a template and an input page to build the ouput page. Both files have blocks of code surrounded by comments that look like The output file is the template file with all the named blocks replaced by the corresponding block in the input file. The effect is that all code outside the named blocks are updated. The arguments are input file names. Names can either be individual files or directories. If names are directories, all html files in that directory and its subdirectories will be processed. Html files are identified by their extension. Usually this is specified by the configuration variable DEFAULT_HTML_EXTENSION, but this can be overridden by the -x flag. If no files are passed on the command line, the script processes the files in the directory specified by the configuration variable DEFAULT_DIRECTORY. Followme has three flags which override script defaults =over 4 =item -x (html extension) Followme only processes files with an html extension. The argument to this flag overrides the default extension. =item -t (template file) The argument to this flag explicitly sets the name of the template file. =item -m (override check) By default followme will not process an html file that contains a block that is missing in the template. This prevents conent from being lost during the update. The -m flag overrides that check. =back =head1 AUTHOR Bernie Simon (http://carelesshand.net) =head1 LICENSE Copyright Bernard Simon, 2005. You may use this file as you wish as long as this copyright notice is maintained.