#!/usr/local/bin/perl # # $Id: build-web.pl,v 1.4 2003/09/14 20:52:05 bc Exp $ # # ***** BEGIN LICENSE BLOCK ***** # Version: MPL 1.1/GPL 2.0/LGPL 2.1 # # The contents of this file are subject to the Mozilla Public License Version # 1.1 (the "License"); you may not use this file except in compliance with # the License. You may obtain a copy of the License at # http://www.mozilla.org/MPL/ # # Software distributed under the License is distributed on an "AS IS" basis, # WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License # for the specific language governing rights and limitations under the # License. # # The Original Code is Netscape code. # # The Initial Developer of the Original Code is # Netscape Corporation. # Portions created by the Initial Developer are Copyright (C) 2001 # the Initial Developer. All Rights Reserved. # # Contributor(s): Bob Clary # Contributor(s): Bob Clary # # Alternatively, the contents of this file may be used under the terms of # either the GNU General Public License Version 2 or later (the "GPL"), or # the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), # in which case the provisions of the GPL or the LGPL are applicable instead # of those above. If you wish to allow use of your version of this file only # under the terms of either the GPL or the LGPL, and not to allow others to # use your version of this file under the terms of the MPL, indicate your # decision by deleting the provisions above and replace them with the notice # and other provisions required by the GPL or the LGPL. If you do not delete # the provisions above, a recipient may use your version of this file under # the terms of any one of the MPL, the GPL or the LGPL. # # ***** END LICENSE BLOCK ***** # usage # perl build-web.pl --help to get a help page # use File::Copy; use File::Basename; use Cwd; use Pod::Usage; use Getopt::Long; # Global Variables # set $DEBUG to 1 to turn on verbose debugging messages # set $DEBUG to 0 to turn off verbose debugging messages my $DEBUG = 0; # @DEBUGSTACK is used by pushDEBUG and popDEBUG to set local # debugging values. my @DEBUGSTACK = (); if ($ENV{DEBUG}) { $DEBUG=$ENV{DEBUG}; } # Source Files/Directories my %SRCEPHYS; $SRCEPHYS{dirlist} = (); $SRCEPHYS{filelist} = (); # Destination Files/Directories my %DESTPHYS; $DESTPHYS{dirlist} = (); $DESTPHYS{filelist} = (); my $TEMPLATE_CONTENTS_MENU = ''; my $TEMPLATE_CONTENTS_NOMENU = ''; local %WEBDIRMAP; my %FILEDATA = (); my $HTMLFILEREGEXP = '\.html?$'; my $TEXTFILEREGEXP = '(\.xml|\.xul|\.xsl|\.htaccess|\.txt|\.css|\.js|\.map|\.psp|\.php|\.asp|\.pl)$'; my $BINARYFILEREGEXP = '(\.gif|\.jpg|\.jpeg|\.zip|\.tar|\.gz|\.png)$'; my $HELP = ''; my $MAKEPROG = 'make'; my $SRCEPHYSDIR = 'srce'; my $COPY = 'off'; my $SSIPROCESS = 'off'; my $CLEAN = 'off'; my $DIRMAP = ''; my $SRCEWEBDIR = ''; my $DESTPHYSDIR = ''; GetOptions('help' => \$HELP, 'make=s' => \$MAKEPROG, 'srcephysdir=s' => \$SRCEPHYSDIR, 'copy=s' => \$COPY, 'ssiprocess=s' => \$SSIPROCESS, 'cleandest=s' => \$CLEAN, 'dirmap=s' => \$DIRMAP, 'srcewebdir=s' => \$SRCEWEBDIR, 'destphysdir=s' => \$DESTPHYSDIR); pod2usage(-verbose => 2) if $HELP; my $usagemsg = ''; if (!$MAKEPROG || !$SRCEPHYSDIR) { $usagemsg .= "--make and --srcephysdir must be specified\n"; } if ($SSIPROCESS eq 'on') { ; } elsif ($SSIPROCESS eq 'off') { $SSIPROCESS = ''; } else { $usagemsg .= "--ssiprocess must be either on or off\n"; } if ($CLEAN eq 'on') { ; } elsif ($CLEAN eq 'off') { $CLEAN = ''; } else { $usagemsg .= "--clean must be either on or off\n"; } if ($COPY eq 'on') { if ($COPY && (!$SRCEWEBDIR || !$DIRMAP || !$DESTPHYSDIR) ) { $usagemsg .= "--copy requires --dirmap --srcewebdir --destphysdir\n"; } } elsif ($COPY eq 'off') { $COPY = ''; if ($SSIPROCESS eq 'on' || $CLEAN eq 'on' || $DIRMAP || $SRCEWEBDIR || $DESTPHYSDIR) { $usagemsg .= "--ssiprocess=on, --clean=on, --dirmap, --srcewebdir, --destphysdir require --copy\n"; } } else { $usagemsg .= "--copy must be either on or off\n"; } if ($usagemsg) { $usagemsg .= "\nTry build-web.pl --help for more help\n"; pod2usage(-message => $usagemsg, -exitstatus => 1, -verbose => 1); } # remove trailing / from source, destination directory names if (substr($SRCEPHYSDIR, length($SRCEPHYSDIR)-1, 1) eq '/') { chop $SRCEPHYSDIR; } if (substr($DESTPHYSDIR, length($DESTPHYSDIR)-1, 1) eq '/') { chop $DESTPHYSDIR; } die "source dir $SRCEPHYSDIR is not a directory" if (! -d $SRCEPHYSDIR); die "dest dir $DESTPHYSDIR exists and is not a directory" if (-e $DESTPHYSDIR && ! -d $DESTPHYSDIR); # global timestamp set by the templates and include files my $TIMESTAMP = getRealTimeStamp("$SRCEPHYSDIR/timestamp"); my $HTMLTIMESTAMPMENU = getRealTimeStamp("$SRCEPHYSDIR/template.html"); my $HTMLTIMESTAMPNOMENU = getRealTimeStamp("$SRCEPHYSDIR/template-nomenu.html"); build_srce_filelist($SRCEPHYSDIR); debug_msg("\n-- SRCEPHYS --"); dump_loc(\%SRCEPHYS); if ($COPY) { loadWebDirMap(); getTemplates(); createDestDirectories(); # remove entries in destination that are not in source if ($CLEAN) { build_dest_filelist($DESTPHYSDIR); debug_msg("\n-- DESTPHYS --"); dump_loc(\%DESTPHYS); clean_dest('filelist'); clean_dest('dirlist'); } copySrceToDest('filelist'); } if ($COPY) { processMakefilePost($DESTPHYSDIR); } else { processMakefilePost($SRCEPHYSDIR); } exit(0); # # End program # sub build_srce_filelist { # Load the directory and file names from the Source # that are to be copied to Destination my $currpath = shift; _build_srce_filelist($currpath); @{$SRCEPHYS{filelist}} = sort @{$SRCEPHYS{filelist}}; @{$SRCEPHYS{dirlist}} = sort @{$SRCEPHYS{dirlist}}; } sub _build_srce_filelist { my $currpath = shift; debug_msg("_build_srce_filelist(\"$currpath\")"); my $makefile = "$currpath/Makefile.pre"; if (-f $makefile) { $makefile =~ s/^$currpath\///; #pushDEBUG(); debug_msg("_build_srce_filelist: Make path=$currpath file=$makefile"); #popDEBUG(); system("$MAKEPROG -C $currpath -f Makefile.pre > $currpath/$makefile.log 2>&1") == 0 or die "make $currpath/$makefile failed\n"; } my $entry; # Load Directory Names if (!opendir(DIRH, $currpath)) { warn "unable to open directory $currpath, $!\n"; return; } my @tempdirlist = grep -d, map "$currpath/$_", readdir DIRH; closedir DIRH; my @currdirlist = (); foreach $entry (@tempdirlist) { if ($entry =~ /(\.\.?|CVS|_vti_[^\/]*)$/) { ; # Skip ., .., any CVS or FrontPage directories } else { push @currdirlist, $entry; } } # Load File Names if (!opendir(DIRH, $currpath)) { warn "unable to open directory $currpath, $!\n"; return; } my @currfilelist = grep -f, map "$currpath/$_", readdir DIRH; closedir DIRH; my $file; my $realtimestamp; my $othertimestamp; foreach $entry (@currfilelist) { $realtimestamp = getRealTimeStamp($entry); if ($entry =~ /NOWRAP$/) { my $file; open(NOWRAP, $entry) || die "Unable to open $entry, $!\n"; while ($file = ) { chomp $file; $file =~ s/\r//g; next if ($file eq ''); $file = $currpath . '/' . $file; $othertimestamp = getRealTimeStamp($file); if ($othertimestamp > $realtimestamp) { setEffectiveTimeStamp($file, $othertimestamp); } $FILEDATA{$file}{NOWRAP} = 1; debug_msg("NOWRAPFILES [$file]"); } close NOWRAP; } elsif ($entry =~ /NOMENU$/) { my $file; open(NOMENU, $entry) || die "Unable to open $entry, $!\n"; while ($file = ) { chomp $file; $file =~ s/\r//g; next if ($file eq ''); $file = $currpath . '/' . $file; $othertimestamp = getRealTimeStamp($file); if ($othertimestamp > $realtimestamp) { setEffectiveTimeStamp($file, $othertimestamp); } $FILEDATA{$file}{NOMENU} = 1; debug_msg("NOMENUFILES [$file]"); } close NOMENU; } elsif ($SSIPROCESS && $entry =~ /\-incl.html?$/) { ; } elsif ($entry =~ /^$SRCEPHYSDIR\/(template.html|template-nomenu.html)$/) { #print "template file: $entry\n"; } elsif ($entry =~ /Makefile\.(pre|post)$/) { ; } elsif ($entry =~ /(\.cvsignore|\~|\.[bB][aA][kK]|\.swp|timestamp|Makefile\.post\.log|Makefile\.pre\.log)$/) { ; # Skip .cvsignore, and backup files } else { push @{$SRCEPHYS{filelist}}, $entry; } } # Load the subdirectories foreach $entry (@currdirlist) { _build_srce_filelist($entry); } push @{$SRCEPHYS{dirlist}}, @currdirlist; } sub build_dest_filelist { # Load the directory and file names from the Destination my $currpath = shift; _build_dest_filelist($currpath); if (defined(@{$DESTPHYS{filelist}})) { @{$DESTPHYS{filelist}} = sort @{$DESTPHYS{filelist}}; } if (defined(@{$DESTPHYS{dirlist}})) { @{$DESTPHYS{dirlist}} = sort @{$DESTPHYS{dirlist}}; } } sub _build_dest_filelist { my $currpath = shift; debug_msg("_build_dest_filelist(\"$currpath\")"); my $entry; # Load Directory Names if (!opendir(DIRH, $currpath)) { warn "unable to open directory $currpath, $!\n"; return; } my @tempdirlist = grep -d, map "$currpath/$_", readdir DIRH; closedir DIRH; my @currdirlist = (); foreach $entry (@tempdirlist) { if ($entry =~ /\.\.?$/) { ; # Skip ., .. } else { push @currdirlist, $entry; } } # Load File Names if (!opendir(DIRH, $currpath)) { warn "unable to open directory $currpath, $!\n"; return; } my @currfilelist = grep -f, map "$currpath/$_", readdir DIRH; closedir DIRH; foreach $entry (@currfilelist) { push @{$DESTPHYS{filelist}}, $entry; } # Load Subdirectories foreach $entry (@currdirlist) { _build_dest_filelist($entry); } push @{$DESTPHYS{dirlist}}, @currdirlist; } sub clean_dest { # Remove entries from Destination that are not in the Source my $arrayname = shift; debug_msg("clean_dest(\"$arrayname\")"); my $isrce; my $idest; my $srcefile; my $destfile; my $tempfile; $isrce = 0; $srcefile = $SRCEPHYS{$arrayname}[$isrce]; foreach $destfile (@{$DESTPHYS{$arrayname}}) { debug_msg("clean_dest: dest $destfile"); debug_msg("clean_dest: srce $srcefile"); $tempfile = $srcefile; $tempfile =~ s/^$SRCEPHYSDIR/$DESTPHYSDIR/o; while ($tempfile lt $destfile && $isrce <= $#{$SRCEPHYS{$arrayname}}) { $srcefile = $SRCEPHYS{$arrayname}[$isrce++]; $tempfile = $srcefile; $tempfile =~ s/^$SRCEPHYSDIR/$DESTPHYSDIR/o; } if ($tempfile gt $destfile) { if (-d $destfile) { debug_msg("clean_dest(\"$arrayname\"): rmdir $destfile"); rmdir $destfile; } else { debug_msg("clean_dest(\"$arrayname\"): unlink $destfile"); unlink $destfile; } } } } sub readFileIntoString { # read the contents of a file and return as a string my $file = $_[0]; my $text = \$_[1]; debug_msg("readFileIntoString(\"$file\", \"...\")"); open(FILE, "<$file") || die "readFileIntoString: Can't open file: $file from " . cwd() . " Error: $!\n"; $$text = join("", ); #XXXbc: Hack problem in Cygwin with embedded \r #$$text =~ s/\r//g; debug_msg("readFileIntoString(\"$file\", $$text)"); close(FILE); } sub writeFileFromString { # write a file from a string my $file = $_[0]; my $text = \$_[1]; debug_msg("writeFileFromString(\"$file\", $$text)"); #my $dirname = dirname($file); #if (! -d $dirname) #{ # createPath($dirname); #} open(FILE, ">$file") || die "writeFileFromString: Can't open file: $file from " . cwd() . ", Error: $!\n"; print FILE $$text; close(FILE); } sub mapWebDirectories { # remap webdirectorys my $str = \$_[0]; debug_msg("ENTER mapWebDirectories($$str)"); my $olddir; my $newdir; foreach $olddir (keys %WEBDIRMAP) { $newdir = $WEBDIRMAP{$olddir}; debug_msg("map OLD $olddir to $newdir"); $$str =~ s/$olddir/$newdir/sg; } debug_msg("EXIT mapWebDirectories($$str)"); } sub createDestDirectories { return if (!$COPY); # create destination directories to match the source directories my $srceentry; my $destentry; my $srcetimestamp; my $desttimestamp; debug_msg("createDestDirectories"); # Create Destination Directory $srcetimestamp = getRealTimeStamp($SRCEPHYSDIR); if (! -d $DESTPHYSDIR) { debug_msg("createDestDirectories: $DESTPHYSDIR"); mkdir $DESTPHYSDIR, 0777 || die "error mkdir $DESTPHYSDIR : $!\n"; } utime $srcetimestamp, $srcetimestamp, ($DESTPHYSDIR); # Create Destination Subdirectories foreach $srceentry (@{$SRCEPHYS{dirlist}}) { $srcetimestamp = getRealTimeStamp($srceentry); $destentry = $srceentry; $destentry =~ s/^$SRCEPHYSDIR/$DESTPHYSDIR/o; debug_msg("srceentry=$srceentry"); debug_msg("destentry=$destentry"); if (! -d $destentry) { debug_msg("create: $destentry"); mkdir $destentry, 0777 || die "error mkdir $destentry : $!\n"; } else { debug_msg("$destentry Exists"); } utime $srcetimestamp, $srcetimestamp, ($destentry); } } sub processMakefilePost { # perform Makefile.post processing my $srceentry; my $destentry; debug_msg("performMakefilePost"); # Destination Subdirectories foreach $srceentry (@{$SRCEPHYS{dirlist}}) { $destentry = $srceentry; if ($COPY) { $destentry =~ s/^$SRCEPHYSDIR/$DESTPHYSDIR/o; } debug_msg("srceentry=$srceentry"); debug_msg("destentry=$destentry"); if (-f "$srceentry/Makefile.post") { debug_msg("performMakefilePost directory $destentry"); if ($COPY) { copy("$srceentry/Makefile.post", "$destentry/Makefile.post"); } system("$MAKEPROG -C $destentry -f Makefile.post > $destentry/Makefile.post.log 2>&1") == 0 or die "make $destentry/Makefile.post failed\n"; if ($COPY) { # remove the Makefile from the destination copy("$destentry/Makefile.post.log", "$srceentry/Makefile.post.log"); unlink "$destentry/Makefile.post"; unlink "$destentry/Makefile.post.log"; } } } } sub copySrceToDest { # Copy Files from Source Directories to Destination Directories my $arrayname = shift; #pushDEBUG(); debug_msg("copySrceToDest(\"$arrayname\")"); #popDEBUG(); my $srceentry; my $srcetimestamp; my $realtimestamp; my $destentry; my $desttimestamp; my $filecontents = ''; my $docopy; my $filetype; my $thissrcedirname = ''; my $lastsrcedirname = ''; my $thisdestdirname = ''; my $lastdestdirname = ''; foreach $srceentry (@{$SRCEPHYS{$arrayname}}) { $docopy = 0; $destentry = $srceentry; $destentry =~ s/^$SRCEPHYSDIR/$DESTPHYSDIR/o; $thissrcedirname = dirname($srceentry); $thisdestdirname = dirname($destentry); $effectivetimestamp = getEffectiveTimeStamp($srceentry); $realtimestamp = getRealTimeStamp($srceentry); $desttimestamp = getRealTimeStamp($destentry); #print "$srceentry: TimeStamps: Effective $effectivetimestamp, Real $realtimestamp, Dest $desttimestamp\n"; if ($thissrcedirname ne $lastsrcedirname) { if (! -d $thisdestdirname) { #pushDEBUG(); debug_msg("copySrceToDest: creating directory $thisdestdirname"); #popDEBUG(); createPath($thisdestdirname); } } if ($srceentry =~ /$HTMLFILEREGEXP/oi) { $filetype = 'H'; if ($effectivetimestamp > $desttimestamp) { # copy srce if dest / srce modification times do not agree # note files that not not exist will return timestamp -1 $docopy = 1; } elsif (defined($FILEDATA{$srceentry}{NOWRAP})) { } elsif (defined($FILEDATA{$srceentry}{NOMENU})) { if ($HTMLTIMESTAMPNOMENU > $desttimestamp) { # copy srce if the NOMENU template changed $docopy = 1; } } else { if ($HTMLTIMESTAMPMENU > $desttimestamp) { # copy srce if the MENU template changed $docopy = 1; } } } else { if ($srceentry =~ /$TEXTFILEREGEXP/oi) { $filetype = 'T'; } elsif ($srceentry =~ /$BINARYFILEREGEXP/oi) { $filetype = 'B'; } else { $filetype = 'B'; } if ($effectivetimestamp > $desttimestamp) { # copy srce if dest / srce modification times do not agree # note files that not not exist will return timestamp -1 $docopy = 1; } } #pushDEBUG(); debug_msg("copySrceToDest: $srceentry $filetype docopy=$docopy Timestamp Real $realtimestamp, Effective $effectivetimestamp Dest $desttimestamp"); #popDEBUG(); if ($docopy && $COPY) { #pushDEBUG(); debug_msg("copySrceToDest: COPY $filetype $srceentry Timestamp Real $realtimestamp, Effective $effectivetimestamp Dest $desttimestamp"); #popDEBUG(); if ($filetype eq 'H') { readFileIntoString($srceentry, $filecontents); if ($SSIPROCESS eq 'on') { processSSI($srceentry, $filecontents); } applyHtmlTemplates($srceentry, $filecontents, $realtimestamp); mapWebDirectories($filecontents); writeFileFromString($destentry, $filecontents); } elsif ($filetype eq 'T') { readFileIntoString($srceentry, $filecontents); mapWebDirectories($filecontents); writeFileFromString($destentry, $filecontents); } elsif ($filetype eq 'B') { copy($srceentry, $destentry); # copy binary files } utime $realtimestamp, $realtimestamp, ($destentry); } $lastsrcedirname = $thissrcedirname; $lastdestdirname = $thisdestdirname; } } sub loadWebDirMap { debug_msg("loadWebDirMap"); return if (!$COPY); require $DIRMAP || die "failed to load $DIRMAP\n"; if ($DEBUG) { my $key; foreach $key (keys %WEBDIRMAP) { print "map $key to $WEBDIRMAP{$key}\n"; } } } sub processSSI { my $filepath = $_[0]; my $filecontents = \$_[1]; debug_msg("ENTER processSSI(\"$filepath\", $$filecontents)"); my $inclregexp = ""; my $currpath = dirname($filepath); my $includefile; my $includefilecontents; my (@directives) = ($$filecontents =~ /($inclregexp)/gi); foreach $directive (@directives) { debug_msg("$directive"); if ($directive =~ /file=/i) { ($includefile) = ($directive =~ /file=\"([^\"]*?)\"/); if ($includefile =~ /^\//) { debug_msg("absolute file path"); # already absolute,... } else { # prepend the current directory to make relative into absolute path debug_msg("relative file path"); $includefile = $currpath . '/' . $includefile; } readFileIntoString($includefile, $includefilecontents); #debug_msg("\nBEGIN INCLUDE $includefile:\n\n$includefilecontents\nEND INCLUDE\n"); $$filecontents =~ s/$directive/$includefilecontents/; } elsif ($directive =~ /virtual=/i) { ($includefile) = ($directive =~ /virtual=\"([^\"]*?)\"/); if ($includefile =~ /^\//) { # convert absolute virtual path to absolute physical path die "absolute virtual path $includefile in file $filepath does not begin with $SRCEWEBDIR" if (!($includefile =~ /$SRCEWEBDIR/o)); debug_msg("absolute virtual path"); debug_msg("includefile before=$includefile"); $includefile =~ s/^$SRCEWEBDIR/$SRCEPHYSDIR/o; debug_msg("includefile after=$includefile"); } else { # prepend the current directory to make relative into absolute path debug_msg("relative virtual path"); debug_msg("includefile before=$includefile"); $includefile = $currpath . '/' . $includefile; debug_msg("includefile after=$includefile"); } readFileIntoString($includefile, $includefilecontents); #debug_msg("\nBEGIN INCLUDE $includefile:\n\n$includefilecontents\nEND INCLUDE\n"); $$filecontents =~ s/$directive/$includefilecontents/; } else { die "unknown SSI $directive in file $filepath\n"; } } mapWebDirectories($$filecontents); debug_msg("EXIT processSSI(\"$filepath\", $$filecontents)"); } sub applyHtmlTemplates { my $filepath = $_[0]; my $filecontents = \$_[1]; my $filetimestamp = $_[2]; my $template; debug_msg("ENTER applyHtmlTemplates(\"$filepath\", $$filecontents)"); if ($FILEDATA{$filepath}{NOWRAP}) { #pushDEBUG(); debug_msg("applyHTMLTemplates: NOWRAP $filepath"); #popDEBUG(); debug_msg("applyHtmlTemplates NOWRAP $filepath"); return; } if ($$filecontents =~ /]*>)||i; $doctype = $1; if (!$doctype) { $doctype = ''; } $$filecontents =~ s|]*>||gomi; # $head now contains the contents of the HEAD tag # not including the containing HEAD tags. This will # allow the template to contain information in it's HEAD # and have it added to the output documents. $head = ""; if ($$filecontents =~ s|()(.*)()||si) { $head .= $2; } # if there's still a tag, that means the document didn't # have a proper <head> section so we'll give it one. if ($$filecontents =~ s|(<TITLE>[^<]*)||i) { $head .= $1; } #extract the title ($title) = $head =~ m|([^<]*)|i; if (!$title) { $title = ''; } my ($bodytag) = ($$filecontents =~ m|(]*>)|i); # if the page is a frameset with a noframes and a \ # body inside of the noframes we don't want to treat it as # if it has a body, so remove it. if ($bodytag) { debug_msg("applyHtmlTemplates: name=$filename, replace with $bodytag"); # remove body tag $$filecontents =~ s|]*>||gi; my ($templatebodyattr) = ($template =~ m|]*)>|i); my ($localbodyattr) = ($bodytag =~ m|]*)>|i); if (!$templatebodyattr) { $templatebodyattr = ''; } if (!$localbodyattr) { $localbodyattr = ''; } debug_msg("applyHtmlTemplates: templateattr=$templatebodyattr, localbodyattr=$localbodyattr\n"); $template =~ s|]*>||i; } else { # no body tag in input file, remove from template debug_msg("applyHtmlTemplates: no body tag in input, remove from template\n"); $template =~ s|]*>||goi; } $template =~ s/%%BODY%%/$$filecontents/; $$filecontents = $template; $template = ''; $$filecontents =~ s/%%DOCTYPE%%/$doctype/; $$filecontents =~ s/%%HEAD%%/$head/; $$filecontents =~ s/%%TITLE%%/$title/g; $$filecontents =~ s/%%LAST_UPDATED%%/$last_updated/g; $$filecontents =~ s/%%FILENAME%%/$filename/g; debug_msg("EXIT applyHtmlTemplates(\"$filepath\", $$filecontents)"); } sub getTemplates { debug_msg("getTemplates"); if (-f "$SRCEPHYSDIR/template.html") { readFileIntoString("$SRCEPHYSDIR/template.html", $TEMPLATE_CONTENTS_MENU); if ($SSIPROCESS eq 'on') { processSSI("$SRCEPHYSDIR/template.html", $TEMPLATE_CONTENTS_MENU); } mapWebDirectories($TEMPLATE_CONTENTS_MENU); } if (-f "$SRCEPHYSDIR/template-nomenu.html") { readFileIntoString("$SRCEPHYSDIR/template-nomenu.html", $TEMPLATE_CONTENTS_NOMENU); if ($SSIPROCESS eq 'on') { processSSI("$SRCEPHYSDIR/template-nomenu.html", $TEMPLATE_CONTENTS_NOMENU); } mapWebDirectories($TEMPLATE_CONTENTS_NOMENU); } } sub createPath { my $dirname = shift; my @pathlist = split '/', $dirname; my $currdir = ''; my $subdir; foreach $subdir (@pathlist) { $currdir = $currdir . $subdir . '/'; if (! -d $currdir) { mkdir $currdir, 0777 or die "unable to create $currdir from " . cwd() . ": $!\n"; } } } # # time stamp stuff # sub getRealTimeStamp { my $file = shift; my $timestamp = 0; $timestamp = $FILEDATA{$file}{realtimestamp}; if (!$timestamp) { if (-e $file) { $timestamp = (stat $file)[9]; } else { $timestamp = -1; } $FILEDATA{$file}{effectivetimestamp} = $FILEDATA{$file}{realtimestamp} = $timestamp; } return $timestamp; } sub getEffectiveTimeStamp { my $file = shift; my $timestamp = 0; $timestamp = $FILEDATA{$file}{effectivetimestamp}; if (!$timestamp) { if (-e $file) { $timestamp = (stat $file)[9]; } else { $timestamp = -1; } $FILEDATA{$file}{effectivetimestamp} = $FILEDATA{$file}{realtimestamp} = $timestamp; } return $timestamp; } sub setEffectiveTimeStamp { my $file = shift; my $timestamp = shift; my $effectivetimestamp = getEffectiveTimeStamp($file); #pushDEBUG(); debug_msg("setEffectiveTimeStamp: file=$file, timestamp=$timestamp, effectivetimestamp=$effectivetimestamp"); #popDEBUG(); if ($timestamp > $effectivetimestamp) { $effectivetimestamp = $FILEDATA{$file}{effectivetimestamp} = $timestamp; } return $effectivetimestamp; } # # debugging stuff # sub debug_msg { # print a debug message to STDOUT print "DEBUG: $_[0]\n" if ($DEBUG); } sub pushDEBUG { push @DEBUGSTACK, $DEBUG; $DEBUG = 1; } sub popDEBUG { $DEBUG = pop @DEBUGSTACK; } sub dump_loc { if ($DEBUG) { my $locref = shift; print "\n== dirlist ==\n"; print join "\n", @{$$locref{dirlist}}; print "\n== filelist ==\n"; print join "\n", @{$$locref{filelist}}; } } __END__ =head1 build-web.pl Build Web Sites =head1 SYNOPSIS build-web.pl [options] =head1 OPTIONS =over 8 =item B<--help> Display this help page. =item B<--make>=I Specify make program to be used. Default value is I. =item B<--srcephysdir>=I Specify the path to the physical directory containing the raw html to be processed. Default value is I. =item B<--copy>=I<[on|off]> Write the results to the destination physical directory. If B<--copy>=I is specified then only the pre and post makefile processing is performed. B<--copy>=I requires that the B<--srcewebdir>, B<--destphysdir> and B<--dirmap> options be specified. =item B<--srcewebdir>=I Assume the raw html contained in the srcephysdir is written as if the root web directory is I. Requires B<--copy>=I =item B<--destphysdir>=I Write the results of processing the web site to the physical directory I. Requires B<--copy>=I =item B<--ssiprocess>=I<[on|off]> Replace the results of Server Side includes (virtual and file only) with the contents of the included files. Default value is I. Requires B<--copy>=I =item B<--dirmap>=I Replace occurences of directories using the map specified in the I script. Requires B<--copy>=I =item B<--clean>=I<[on|off]> Remove files from the destphysdir if they do not exist in the srcephysdir. Default value is I. Requires B<--copy>=I =back =head1 DESCRIPTION If B<--copy>=I, build-web.pl will build a Web Site in a given Physical Destination directory from a Web Site contained in a given Source directory by copying the files from the Physical Source directory tree to the Physical Destination directory tree while remapping directory paths as specified in the "DIRMAP.pl" perl program, optionally processing Server Side includes, and optionally applying HTML Templates to HTML files. The Source Web Site exists in the physical directory SRCEPHYSDIR and is assumed to be written as it were located on a Web Server in the SRCEWEBDIR subdirectory of the Server's root directory. This program essentially copies a Physical Source Directory and all subdirectories and files to a Destination Directory while performing the following tasks. If Makefiles exist in the Source Directories, they are 'executed' using the make program specified in B<--make>=I. Makefiles with the name "Makefile.pre" will be executed in the Physical Source directory tree before any other processing and can produce new files which will be copied to the Physical Destiantion directory tree. Makefiles with the name "Makefile.post" will be executed in the Destination directory tree and can be used to post process output files generate during the build... For example, zip files of the final versions of files in the DEST directory tree can be created using post Makefiles. In the case where B<--copy>=I, the Physical Source and Destination directories are the same and post Makefiles are executed in the Physical Source directory. If the Destination Directories do not exist, they are created. Source Files are not copied if their modification times are not different from the modification times of the existing Destination files. This rule is broken when the template files, include files or Makefiles are modified. A Global timestamp is maintained on the last time the build was run. If any of the templates, include files, Makefiles are modified after the last build, all files are rebuilt. The following Source Directories are not copied: CVS, _vti_* The following Source Files are not copied: Makefile.pre, Makefile.post, Makefile.log, NOWRAP, NOMENU, *-incl.html, template.html, template-nomenu.html, .cvsignore, *~, *.bak, *.swp If the B<--clean>=I option is specified, files which exist in the Destination Directories but not in the Source Directories are deleted from the Destination Directories. Binary Files are copied as is. Text Files (not HTML files, i.e. *.htm or *.html) are copied with directory remapping as specified in "DIRMAP.pl". The DIRMAP.pl program specifies the remapping of referenced directories in all Text files. These include *.js, *.css, *.htm, *.html, *.psp, *.php, *.asp, *.pl files. DIRMAP.pl, which can be named anything, consists of a single Hash which specifies the old=>new directory remapping as in: $WEBDIRMAP{'/fromdir/'} = '/todir/'; Note that WEBDIRMAP must contain at least a mapping for the SRCEWEBDIR to a new Web Server directory. HTML Files are copied with directory remapping, then Server Side includes, then HTML Template wrapping. Server Side includes in HTML Files are replaced by the contents of the included files. The included files must reside in the SRCEPHYDIR tree and are not copied to the Destination Directories. The Server Side includes may be either file or virtual, but typically virtual is the most useful. HTML Templates are specified in special files in the SRCEPHYSDIR directory template.html - full template including navigation template-nomenu.html - template wihthout full navigation By default, all HTML files will be wrapped in the template.html template. This may be overridden in each directory by listing the filename on distinct lines in either the NOMENU or NOWRAP text files in each directory. Any file listed in the NOMENU file will be wrapped with the template-nomenu.html file, while any file listed in the NOWRAP file will not be wrapped in a template at all. However, all HTML Files will have their references to directories remapped according to the DIRMAP.pl program. Each Template file uses special strings which are replaced by the corresponding parts of the HTML file being wrapped: %%DOCTYPE%% %%HEAD%% %%TITLE%% %%LAST_UPDATED%% %%BODY%% %%FILENAME%% =cut # eof: build-web.pl