#!/usr/bin/perl -w ################################################################################ # # makeweb - create websites from templates # Version: 0.3 # # Author: Tim Retout # Email: tim (at) retout (dot) co (dot) uk # Created: 20th November 2004 # Last Changed: 18th January 2005 # # Changelog # --------- # # 2004-11-20 0.1 Created file; detects the directories, but does nothing. # 2005-01-07 0.2 Rewrote half. Added lots. It actually works now, except for doing any generation of HTML. # 2005-01-18 0.3 Added CGI::Pretty HTML generation - added header/footer content. # ################################################################################ use strict; use File::Spec; use File::Find; use File::Basename; use File::Path; use File::Copy qw( cp ); use CGI::Pretty qw( :html ) ; use Time::localtime; # We're going to generate websites automatically, based upon a set of templates and some input text files. # # First, a directory structure: # $MainDir is the base directory. It should contain directories for each website under development. # In each website directory should be: # $InputDir - Plain text files, containing content in some structured form. # $OutputDir - Outputted html files # # Each plain text file should contain all the data to generate a single page. # What the hell, let's just stick Perl variables in there, and evaluate the page. It's simpler in the long run. # # Then all this program needs to do is work through the files under each $InputDir, and throw together some output files. # It only tries to process files ending in '.in'. All others are just copied verbatim. # # ToDo # ---- # # Content for the columns. # # One thing to consider is the navigation bar - hmm. # # Also, this must work with different websites - I'm not going to design this tool 3000 more times. # So command line options might be nice. # Initialise variables. use vars qw( $Title @Keywords ); ################################################################################ # # Configuration. # ################################################################################ my $MainDir = '/home/tim/websites'; my $TimeStamp = '0'; # For having different versions of each website. my $Verbose = '1'; my $VeryVerbose = '0'; $Verbose = '1' if ($VeryVerbose); ################################################################################ # # Take main directory and extract website names; call &ProcessEachWebsite on each. # ################################################################################ opendir (MAINDIR, $MainDir) or die "Can't open $MainDir: $!"; for (readdir MAINDIR) { next if (/^\./); next unless (-d File::Spec->catfile($MainDir,$_)); &ProcessEachWebsite($_); } ################################################################################ # # Process each website. # ################################################################################ sub ProcessEachWebsite { my $WebsiteName = shift; my $WebsiteDir = File::Spec->catfile($MainDir,$WebsiteName); my $InputDir = File::Spec->catfile($WebsiteDir,'plain'); my $OutputDir = File::Spec->catfile($WebsiteDir,'html'); $OutputDir .= '.' if $TimeStamp; $OutputDir .= time if $TimeStamp; my @FileList; my @ExtraFileList; find( # Finds all the files in $InputDir, and categorises them. sub { # Begin anonymous subroutine. my $File = $File::Find::name; if (-f $File) { if (/^\./) { # Do nothing for hidden files. } elsif (/\.in$/) { # Process '.in' files. push @FileList, $File; } else { # Copy all other files. push @ExtraFileList, $File; } } } # End of subroutine. ,$InputDir); # Finish the 'find' command. ######################### # May want to process a config file at this point. # We now have a list of all the files which are going to be processed in @FileList. # And a list of all the files to be copied over in @ExtraFileList ######################### print "Website: $WebsiteName\n" if $Verbose; rmtree ($OutputDir,$VeryVerbose,'1'); for (@FileList) { my $ShortName = $_; $ShortName =~ s/^$InputDir.//; $ShortName =~ s/\.in$//; my $OutputFile = File::Spec->catfile($OutputDir,$ShortName); my $OutputPath = dirname($OutputFile); print " Generating ", $ShortName, " ... " if $Verbose; print "\n" if $VeryVerbose; #open (INPUT, "< $_") or die "Can't write to $_: $!"; mkpath($OutputPath,$VeryVerbose,0777) unless (-d $OutputPath); open (OUTPUT, "> $OutputFile") or die "Can't write to $OutputFile: $!"; ################################ # Call a bunch of subroutines. # ################################ $Title = ""; # Make sure this is empty. @Keywords = (); # And this as well. do $_; #next unless %Page; print OUTPUT &ProducePage; ################################ # That was the exciting bit. # ################################ close OUTPUT; #close INPUT; print "done.\n" if $Verbose; } for (@ExtraFileList) { my $ShortName = $_; $ShortName =~ s/^$InputDir.//; my $OutputFile = File::Spec->catfile($OutputDir,$ShortName); my $OutputPath = dirname($OutputFile); print " Copying ", $ShortName, " ... " if $Verbose; print "\n" if $VeryVerbose; mkpath($OutputPath,$VeryVerbose,0777) unless (-d $OutputPath); cp($_,$OutputFile); print "done.\n" if $Verbose; } print "\n" if $Verbose; } ################################################################################ # # Produce each page. # ################################################################################ sub ProducePage { #################################### my $XmlDeclaration = q{}; my $DoctypeDeclaration = q{}; # Note: on two lines. my $MetaContentType = meta({'http-equiv'=>'Content-Type',content=>'text/html; charset=utf-8'}); my $MetaKeywords = meta({name=>'keywords',content=>join ", ", @Keywords}); # TODO: This next bit should be done differently. Works for now. my $Stylesheet = Link({href=>'styles/default.css',rel=>'stylesheet',type=>'text/css'}); #################################### my $page; $page .= "$XmlDeclaration\n"; $page .= "$DoctypeDeclaration\n"; $page .= head( $MetaContentType, $MetaKeywords, title($Title), $Stylesheet ); $page .= body( div( {id=>'container'}, &ReturnHeaderDiv, &ReturnColumnsDiv, &ReturnFooterDiv ) ); return $page; # Write to OUTPUT. } sub ReturnHeaderDiv { # TODO: The h1 title should be independent of the page title. div( {id=>'header'}, div( h1($Title) ) ); } sub ReturnColumnsDiv { # TODO: Content here. div( {id=>'columns'}, div( {id=>'columns_float'}, ), div( {id=>'left'}, ) ); } sub ReturnFooterDiv { my $Copyright = '&169; '. (localtime->year() + 1900) . ' Tim Retout.'; my $Maintainer = 'Maintained by Tim Retout.'; # TODO: This could be rewritten to use file modification times. my $LastRevised = "Last Revised: " . ctime(); div( {id=>'footer'}, div( p( $Copyright, br(), $Maintainer, br(), $LastRevised ) ) ); }