root/swish_website/bin/build

Revision 1910, 26.0 kB (checked in by moseley, 1 year ago)

Adjust date on doc pages and a bit more verbose options on page generation.

  • Property svn:eol-style set to native
  • Property svn:executable set to *
  • Property svn:keywords set to Author Date Id Revision
Line 
1 #!/usr/bin/env perl
2 #!/usr/bin/perl -w
3 use strict;
4 use warnings;
5 use FindBin qw'$Bin $RealBin';
6 use Template;
7
8
9 #=======================================================================
10 # Sat Jan  8 06:56:06 PST 2005 - moseley
11 #
12 # Script to build the swish-e web site and pod docs.  Based on
13 # script written by Peter Karman.  Peter made it look too simple, so
14 # I rewrote it to make it much more complex.
15 #
16 # The script exits true (zero) if ANY files are processed.
17 #
18 # Maintains a cache of table of contents from the pod files so that
19 # only changes need to be updated (docs/index.html knows when to get generated)
20 #
21 # This roughly follows the examples in the Badger book, chapter 11.
22 #
23 # Questions/TODO
24 #   Should utime the output files to match timestamp of input?
25 #   Might be useful is reading from cvs or where someone's machine
26 #   might be off in time
27 #
28 #   Currenly, the download dirs are defined in lib/config/site.
29 #   Means can't easily check to see if those pages need to be updated.
30 #   Since they don't change often, just do a -all run once a day (to catch
31 #   the swish-daily updates).
32 #
33 #   -src sucks as a name.  Is that the location of the source html files?
34 #   No, it's the top-level directory because it expects lib and src
35 #   to be subdirectories.
36 #
37 #========================================================================
38
39 $ENV{TZ} = 'UTC';  # Show all dates in UTC
40
41 # List of pod files relative to INCLUDE_PATH
42 # swish.css is needed for stand-alone html docs.
43
44
45 use vars '$exit_value';
46 $exit_value = 1;  # no files processed yet.
47
48 my @pod_files = qw(
49     pod/README.pod
50     pod/INSTALL.pod
51     pod/CHANGES.pod
52     pod/SWISH-CONFIG.pod
53     pod/SWISH-RUN.pod
54     pod/SWISH-SEARCH.pod
55     pod/SWISH-FAQ.pod
56     pod/SWISH-BUGS.pod
57     pod/SWISH-3.0.pod
58     pod/SWISH-LIBRARY.pod
59     perl/API.pm
60     example/swish.cgi.in
61     example/search.cgi.in
62     prog-bin/spider.pl.in
63     filters/SWISH/Filter.pm.in
64     pod_toc/index.html
65     swish.css
66 );
67
68 my @src_dirs = File::Spec->splitdir( $RealBin );
69 pop @src_dirs;
70 my $src_default     = File::Spec->catfile( @src_dirs );
71 # my $dest_default    = File::Spec->catfile( $src_default, 'public_html' );
72 # my $poddest_default = File::Spec->catfile( $dest_default, 'docs' );
73
74
75 my @argv = @ARGV;  # save for later.
76
77
78 my %default_paths = (  # relative to --root
79     dest        => 'public_html',
80     indexes     => 'indexes',
81     swishsrc    => 'swish_release_build/latest_swish_build/source',
82     develsrc    => 'swish_daily_build/latest_swish_build/source',
83     download    => 'distribution',
84     daily       => 'swish-daily',
85     archive     => 'archive',
86 );
87
88
89
90
91 my %default_config = (
92     ignore      => [ '.svn', '\b(CVS|RCS)\b', '^#', '\.gz$', '\.swp$'],
93     copy        => [ '\.(ico|pdf|gif|png|jpe?g|htaccess)$' ],
94     include     => ['lib' ],
95     src         => $src_default,
96     websitesrc  => 'src',  # default website source directory relative to -src
97                           # added to INCLUDE_PATH
98     web_site    => 1,
99     dev_site    => 1,
100     lists_site  => 1,
101     svn_site    => 1,
102 );
103
104
105 $SIG{__DIE__} = sub {
106     print STDERR "@_";
107     print STDERR <<EOF;
108
109 $0 usage:
110
111 This script is used to build the swish-e website.  It is
112 also used to build the html documentation from the subversion
113 repository for the swish-e release tarball.
114
115 Please see the README for details of building the site, but in
116 short, to build the site:
117
118     bin/build --root \$ROOT --all
119
120 Will build the site, but assumes all required directories are
121 located in \$ROOT, and the website will also be output \$ROOT/public_html.
122
123 As mentioned above, just the documentation can be written using this
124 program.  Use the --poddest options along to just write the pods.
125 When --poddest doesn't not fall within the location of the website the
126 program assumes it's writing docs for the tarball, and links are adjusted
127 to point to the main swish-e website.
128
129 Options:
130
131     -root=<dir>     = If set, will try and set all the following
132                       using defaults below the directory specified.
133                       See README.
134     -all            = don't check timestamps on destination files
135                       Will generate all files, not just ones with
136                       dates newer than the output files.
137     -verbose        = verbose
138     -debug          = eh, debuging output
139     -dryrun         = Don't write output file.
140
141
142     If not using the default locations, these can be set specifically:
143
144     -dest=<dir>     = destination directory for website
145     -indexes=<dir>  = Path to directory where indexes are stored
146     -swishsrc=<dir> = toplevel directory of swish-e source package
147     -develsrc=<src> = Directory of development.
148     -download=<dir> = Path to directory where downloads are located
149     -daily=<dir>    = Path to directory where daily builds are located
150     -archive=<dir>  = Path to the hypermail archive
151
152     -- Normally not needed --
153     -src=<dir>      = top-level directory of website source
154                       Default: $default_config{src}
155                       \$src/src and \$src/lib are INCLUDE_PATH
156     -poddest        = where pods are stored (must set -swishsrc)
157                       Setting poddest will disable website generation
158     -podonly        = says do not write website files, only pod files
159                       (set automatically when -poddest != website dir
160
161     -websitesrc     = default dir where website src content is located
162                       Default: $default_config{websitesrc}
163                       Should never be used.
164
165
166     -- options you don't need --
167     -copy           = add regex to files that are just copies
168     -include        = add directories to the include path
169                       relative to -src unless absolute.
170     -ignore         = add regex of files to skip.
171     -check          = used by swish-e configure
172
173
174     -- Apache config file generation -
175     (Defaults are set in the template and may not match below)
176
177     -apache         = Only generate Apache configuration file.
178                       The file is sent to stdout.
179
180     domain          = Override the domain name [swish-e.org]
181     module_dir      = Location of Apache modules [modules]
182     user            = Apache user [apache]
183     group           = Apache group [apache]
184     logs            = Location of log files [logs]
185     pid_file        = Location of apache pid file [run/httpd.pid]
186     ipaddr          = IP address for Listen statement [*]
187     port            = Port to listen on [80]
188     trac_doc_root   = Path do DocumentRoot for trac [/opt/trac/htdocs]
189     trac_env        = Trac environment [/opt/trac]
190     trac_password   = Trac password file [/opt/svn/swish/conf/dav_svn.passwd]
191     svn_repo        = Path to Subversion Repository [/opt/svn/swish]
192
193     web_site        = Boolean to include website [true]
194     dev_site        = Boolean to include trac site [true]
195     lists_site      = Boolean to include mailman site [true]
196     svn_site        = Boolean to include svn repo [true]
197
198
199     Script exits false (1) if no files are actually processed.
200     Exits false even if -all -dryrun is used.
201     Exits true is at least one file was processed.
202 EOF
203     exit 2;
204     };
205
206 # This sucks because you cannot override arrays with Getopt::Long
207
208
209 my @options = qw(
210     src=s
211     dest=s
212     root=s
213     swishsrc=s
214     poddest=s
215     verbose|v
216     debug
217     all|a
218     ignore=s@
219     copy=s@
220     include=s
221     podonly
222     dryrun|n
223     websitesrc=s
224     abslinks
225     develsrc=s
226     indexes=s
227     download=s
228     daily=s
229     check
230
231     apache
232     domain=s
233     module_dir=s
234     user=s
235     group=s
236     logs=s
237     pid_file=s
238     ipaddr=s
239     port=i
240
241     trac_doc_root=s
242     trac_env=s
243     trac_password=s
244
245     svn_repo=s
246
247     web_site!
248     dev_site!
249     lists_site!
250     svn_site!
251
252 );
253
254
255 my $config = LoadConfig->new( \%default_config, \@options );
256
257 if ( $config->{check} ) {
258     print "a-ok\n";
259     exit(0);
260 }
261
262
263 # Now make the errors a bit more brief
264
265 $SIG{__DIE__} = sub {
266     print STDERR "\n$0:\n  @_\n For Help:\n    $0 --help\n";
267     exit 1;
268 };
269
270 $SIG{__DIE__} = '';
271
272
273
274
275 # Set defaults
276
277     if ( $config->{root} )  {
278         my $root = File::Spec->rel2abs( $config->{root} );
279
280         for my $option ( keys %default_paths ) {
281             next if $config->{$option};
282             my $dir = File::Spec->catfile( $root, $default_paths{$option} );
283
284             if ( -d $dir ) {
285                 $config->{$option} = $dir;
286             } else {
287                 warn "Could not set option '--$option=$dir': $!\n";
288             }
289         }
290     }
291
292
293 # The docs to go to the docs sub-directory by default
294
295     $config->{poddest} = File::Spec->catfile( $config->{dest}, 'docs' )
296         if $config->{dest} && !$config->{poddest};
297
298
299
300
301 # Generate apache config
302
303     if ( $config->{apache} ) {
304
305         my $tt = Template->new(
306             INCLUDE_PATH => File::Spec->catfile( $config->{src}, 'etc' ),
307         );
308
309         my $stash = {
310             %$config,
311             script      => $0,
312             arguments   => join( ' ', @argv ),
313         };
314
315         my $template = $config->{template} || 'httpd.conf.tt';
316
317         $tt->process( $template, $stash ) || die $tt->error;
318
319         exit 0;
320     }
321
322
323
324
325 # Build everything here
326
327
328
329     my $generator = DocBuilder->new( $config );
330
331     # Generate the website
332     if ( $config->dest && !$config->podonly ) {
333         $generator->website;
334
335     } elsif ( $config->verbose ) {
336
337         if ( !$config->dest ) {
338             warn "--dest not defined, not generating website\n";
339         } else {
340             warn "--podonly set, not generating website\n";
341         }
342     }
343
344     # Generate the pods
345     if ( $config->swishsrc ) {
346         $generator->pods( \@pod_files, 'swishsrc' );
347
348     } elsif ( $config->verbose ) {
349         warn "--swishsrc not defined, not generating release docs\n";
350     }
351
352
353
354
355     # Generate the development docs
356     if ( $config->dest && $config->develsrc && !$config->podonly ) {
357         $generator->pods( \@pod_files, 'develsrc' );
358
359     } elsif ( $config->verbose ) {
360
361         if ( !$config->dest ) {
362             warn "--dest not defined, not generating development docs\n";
363         } elsif ( !$config->develsrc ) {
364             warn "--develsrc not defined, not generating development docs\n";
365         } else {
366             warn "--podonly defined, not generating development docs\n";
367         }
368     }
369
370
371
372
373
374     exit $exit_value;
375
376
377 #==============================================================================
378 # Package for containing config and template.
379 #
380 # This sets up and checks various paths and creates the template object
381 # It sets include paths for where source files are found
382 # It sets the OUTPUT_PATH to either the website or to where poddest is set
383 # If poddest is set then only pods are written
384
385
386 package DocBuilder;
387 use strict;
388 use warnings;
389 use File::Spec;
390 use File::Path;
391 use File::Basename;
392 use File::Copy;
393 use Template;
394 use Template::Constants qw( :debug );
395 use Storable;  # cache
396
397 sub new {
398     my ( $class, $config ) = @_;
399
400     $config->{verbose} = 1 if $config->debug;
401
402
403     # Thise have defaults so this should not fail
404     die "Must specify top-level web source directory with -src\n" unless $config->src;
405
406
407     # Validate src directory
408
409     my $topsrc_abs = File::Spec->rel2abs( $config->src );
410     die "src directory [$topsrc_abs] is not a directory\n" unless -d $topsrc_abs;
411     warn "Source directory set to [$topsrc_abs]\n" if $config->verbose;
412
413
414     # Setup for local plugins
415     my $plugin_dir = File::Spec->catfile( $topsrc_abs, 'Plugin' );
416     unshift @INC, $plugin_dir;
417
418
419     # Build include paths - reverse so -include=foo will be pre-pended to path
420     my @includes = map {
421                     File::Spec->file_name_is_absolute( $_ )
422                         ? $_
423                         : File::Spec->rel2abs( $_, $topsrc_abs )
424                     } reverse $config->websitesrc, @{ $config->include };
425
426
427
428     # Validate dest directory
429
430     die "Must specify either -dest (or -root) or -poddest\n"
431         unless $config->dest || $config->poddest;
432
433
434
435     my $dest;
436
437     if ( $config->dest ) {
438         $dest = File::Spec->rel2abs( $config->dest );
439
440         mkdir $dest unless -e $dest;
441
442         die "destination directory [$dest] does not exist\n" unless -e $dest;
443         die "destination directory [$dest] is not a directory\n" unless -d $dest;
444         die "destination directory [$dest] is not writable\n" unless -w $dest;
445         die "Source and destination cannot be the same\n" if $dest eq $topsrc_abs;
446         warn "Destination directory set to [$dest]\n" if $config->verbose;
447     }
448
449
450     # Set pod output location.  Only used if -swishsrc specified
451     my $poddest = File::Spec->rel2abs( $config->poddest );
452
453
454     # If the (website) dest directory is not set then assume we are
455     # writing pods only.
456     # Note: Used to check if the poddest was a sub-directory
457     # of the dest directory, but that was when dest was automatically
458     # set relative to $RealBin.
459
460     unless ( $config->dest ) {
461         $config->{podonly} = 1;  # Don't write the web site
462         $config->{abslinks} = 1; # Flag to generate absolute links on pod files
463         $dest = $poddest;
464     }
465
466
467     # Now deal with -swishsrc for locating pod files
468
469
470     if ( $config->swishsrc ) {
471         my $swish = File::Spec->rel2abs( $config->swishsrc );
472         die "Swish source directory [$swish] is not a directory\n" unless -d $swish;
473         die "Failed to find pod dir [$swish/pod]\n" unless -d "$swish/pod";
474
475         warn "Swish-e source directory set to [$swish]\n" if $config->verbose;
476         warn "PODs will be written to [$poddest]\n" if $config->verbose;
477         $config->{swishsrc} = $swish;
478
479         push @includes, $swish;  # so process() can find the pods (when it's done that way)
480     }
481
482
483     if ( $config->develsrc ) {
484         my $develsrc = File::Spec->rel2abs( $config->develsrc );
485         die "Failed to find devel pod dir [$develsrc/pod]\n" unless -d "$develsrc/pod";
486         warn "Swish-e devel source directory set to [$develsrc]\n" if $config->verbose;
487         $config->{develsrc} = $develsrc;
488     }
489
490
491     # Test the list indexes directory
492     if ( $config->indexes ) {
493         my $index = File::Spec->rel2abs( $config->indexes );
494         die "indexes setting of [$index] is not a directory\n" unless -d $index;
495         $config->{indexes} = $index;
496     }
497
498
499
500     # Validate include directories.
501     for ( @includes ) {
502         die "include directory [$_] is not a directory\n" unless -d $_;
503         warn "Adding template include (lib) directory: [$_]\n" if $config->verbose;
504     }
505
506
507     my $template = Template->new({
508         INCLUDE_PATH    => \@includes,
509         OUTPUT_PATH     => $dest,
510         PLUGIN_BASE     => ['My'],
511
512         # Fix for ignoring case in TT verson 2.15 when loading plugins
513         PLUGINS         => {
514             POD     => 'My::POD',
515         },
516
517         PRE_PROCESS     => 'config/main',
518         WRAPPER         => 'page/wrapper.tt',
519         #PRE_CHOMP       => 1,
520         #POST_CHOMP      => 1,
521         RECURSION       => 1,
522         # DEBUG           => $config->debug ? DEBUG_PROVIDER : 0,
523     } ) || die Template->error;
524
525     my $self = bless  {
526         topdir          => $topsrc_abs,
527         src_dir         => File::Spec->rel2abs( $config->websitesrc, $topsrc_abs ),
528         dest_dir        => $dest,
529         config          => $config,
530         template        => $template,
531         include_path    => \@includes,  # for updating the included path later
532         plugin_dir      => $plugin_dir,
533     }, $class;
534
535     $self->build_accessors;
536
537
538     return $self;
539 }
540
541 sub build_accessors {
542     my ( $self ) = @_;
543
544     no strict 'refs';
545     for my $key ( keys %$self ) {
546         *{$key} = sub { shift->{$key} };
547     }
548 }
549
550 #=========================================================================
551 # pods()
552 # This takes a list of input files relative to $self->swishsrc
553 # and writes all files to one directory: $self->poddest or $self->dest/docs
554 #
555 # Currently, read the file into memory, convert to html and pass that to TT.
556 # TT returns the doc and we write it to the destination ourself.
557 #
558 # The plan is to add $config->swishscr to INCLUDE_PATH and use a plugin
559 # to parse the pod and generate a table of contents and navigation.
560 #
561 # Start off using Peter's existing work.  Much easier that way...
562 #------------------------------------------------------------------------
563 #
564
565 sub pods {
566     my ( $self, $pod_files, $key ) = @_;
567
568
569     # Add source directory to INCLUDE_PATH
570
571     my $src_dir = $config->$key;
572
573     my $include_path = $self->include_path;
574     unshift @$include_path, $src_dir;
575
576
577
578     # Fetch toc cache from disk
579     my $cache_file = File::Spec->catfile( $self->topdir, 'toc_cache.storable' );
580     my $toc_cache;
581
582     eval { $toc_cache = retrieve( $cache_file ) };
583     warn "Cache file [$cache_file] not found\n" if $@;
584     $toc_cache = {} unless ref $toc_cache eq 'HASH';
585
586
587     # Create sub-cache for this source, if doesn't exist
588     # When processing a pod file the POD plugin will update its own cache entry
589     # in the hash.  Cache by source directory
590
591     my $this_toc_cache = $toc_cache->{$src_dir} ||= {};
592
593
594
595
596
597     # set where the docs should be written
598     my $out_prefix = $key eq 'swishsrc' ? 'docs' : 'devel/devel_docs';
599
600     my $version = $self->get_swish_version( $src_dir );
601
602
603     my $update_index = 0;
604
605     for my $in_file ( @$pod_files ) {
606
607         my $out_file = basename( $in_file );
608
609
610         # Change pods to .html
611
612         my $doc_type = '';
613         if ( $out_file =~ /\.(pod|pm|pl|cgi)/ ) {
614             $doc_type = 'pod';
615             ($out_file) = map { s/\.in$//; s/\.(pod|pm|pl)$//; lc($_).'.html' } ($out_file);
616         }
617
618         # Force processing of every pod if there's not cache entry for it.
619         # And force index.html if any pods were processed
620         # Note that '$in_file' ends up as template.name and is key used by POD plugin
621         my $all = $config->all || 0;
622         $config->{all} = 1 if $out_file eq 'index.html' && $update_index;
623         $config->{all} = 1 if $doc_type eq 'pod' && !$this_toc_cache->{$in_file};
624
625
626         # Set destination directory
627         my $abslinks = $self->config->abslinks;
628
629         $out_file = "$out_prefix/$out_file" unless $abslinks;
630
631
632         # Now process it as a template
633         my $vars = {
634             this => {
635                 type        => $doc_type,
636                 page_id     => basename( $out_file ),
637                 podfile     => 1,
638                 abslinks    => $abslinks,
639                 swish_version => $version,
640                 out_file    => $out_file,
641             },
642             mode        => 0644,
643             toc_cache   => $this_toc_cache,  # processing a pod updates this hash
644             pod_files   => $pod_files,       # this is used to generate the toc
645         };
646
647         my $processed = $self->process_file( $in_file, $out_file, $vars );
648
649         $update_index++ if $doc_type eq 'pod' && $processed;  # need to update the index
650                                                 # if any pod files processed
651                                                 # might be better for POD plugin to set flag
652
653         $config->{all} = $all;  # reset (guess I need a set method)
654     }
655
656     # Write out cache
657     store $toc_cache, $cache_file;
658
659
660     shift @$include_path;  # remove source dir.
661
662
663     # Check all the L<> links
664     My::Pod::View::HTML::validate_links($config)
665         if $update_index; # and $config->verbose;
666 }
667
668 #=======================================================================
669 sub get_swish_version {
670     my ( $self, $dir ) = @_;
671     my $version;
672     # look for swish-config
673
674     my $ver;
675     for (
676         "$dir/swish-config",
677         "$dir/../install/bin/swish-config",  # daily build location
678     ) {
679         if ( -x ) {
680             $ver = `$_ --version`;
681             chomp $ver;
682             warn "Found version [$ver] from program $_\n" if $self->config->verbose;
683             return $ver if $ver;
684         }
685     }
686
687     # Now parse from configure.in
688     my $configure = "$dir/configure.in";
689     die "$configure not found\n" unless -f $configure;
690
691     my %version;
692
693     open FH, "<$configure" or die "Failed to open $configure: $!";
694     while ( <FH> ) {
695         next unless /(MAJOR|MINOR|MICRO)_VERSION=(\d+)/;
696         $version{$1} = $2;
697     }
698
699     die "Failed to find version in $configure file\n"
700         unless 3 == keys %version;
701
702     $ver = "$version{MAJOR}.$version{MINOR}.$version{MICRO}";
703     warn "Found version [$ver] from file $configure\n" if $self->config->verbose;
704     return $ver;
705 }
706
707 #=======================================================================
708
709
710 sub logfile {
711     my ( $self, $type, $name, $length ) = @_;
712     return unless $self->config->dryrun || $self->config->verbose || $self->config->debug;
713     my $msg = $self->config->dryrun ? 'Dry Run: ' : '';
714     warn sprintf("${msg}[%-7s] %-40s  %10d Bytes\n", $type, $name, $length );
715 }
716
717
718 #=========================================================================
719 # generate_website()
720 #   Recurses $topsrc/src generating output to $dest
721 #   output files match perms on input file
722 #
723 #   $sub_dir is the directory relative to $self->src_dir
724 #--------------------------------------------------------------------------
725
726
727
728 sub website {
729     my ( $self, $sub_dir ) = @_;
730
731     $sub_dir ||='';  #make File::Spec happy
732
733
734     my ( @files, @dirs );
735
736
737     # Create full path to source directory
738     my $curdir = File::Spec->rel2abs( $sub_dir, $self->src_dir );
739
740     warn "Entering directory [$curdir]\n" if $self->config->debug;
741
742     opendir( DIR, $curdir ) || die "Failed to open dir [$curdir]\n";
743
744     # Grab all files and directories
745     while ( my $file = readdir(DIR) ) {
746         next if $file eq '..' || $file eq '.';
747
748
749         next if $config->test_ignore( $file );  # ignore this file?
750
751         # Set full path to file
752         my $path = File::Spec->catfile( $curdir, $file );
753
754         # Set path relative to $self->src_dir
755         my $rel_path = $sub_dir ? File::Spec->catfile( $sub_dir, $file ) : $file;
756
757         if ( -d $path ) {
758             push @dirs, $rel_path;
759         } else { # $$$ check for -f here?
760             push @files, $rel_path;
761         }
762     }
763
764     close DIR;
765
766     $self->process_file( $_, $_ ) for @files;
767
768     $self->website( $_ ) for @dirs;  # Recurse
769 }
770
771 #=========================================================================
772 # process an input file
773 # pass in:
774 #   $in_file - input file relative to INCLUDE_PATH
775 #   $out_file - output file relative to OUTPUT_PATH
776 #   $options  - hash ref of options to add to $vars
777 #
778 # returns:
779 #   true if processed the file (didn't skip for some reason)
780 #
781 # Checks that input file is newer than output file
782 #-------------------------------------------------------------------------
783
784 sub process_file {
785     my ( $self, $in_file, $out_file, $options ) = @_;
786
787     $options ||= {};
788
789     # Locate the input path in the INCLUDE_PATH
790     my $inpath  = $self->find_in_include( $in_file );
791     die "Failed to find input path for [$in_file].  Aborting.\n" unless $inpath;
792
793
794     my $outpath = File::Spec->rel2abs( $out_file, $self->dest_dir );
795
796     return unless $self->is_newer( $inpath, $outpath );
797
798     unless ( -d dirname( $outpath ) ){
799         mkpath( dirname( $outpath )) unless $self->config->dryrun;
800     }
801
802
803     warn "$inpath->$outpath\n" if $self->config->debug;
804
805
806
807     # Check if only need to copy
808     if ( $self->config->test_copy( $inpath ) ) {
809
810         $self->logfile('Copy', $in_file, (stat $inpath)[7]);
811         return if $self->config->dryrun;
812
813         $main::exit_value = 0;
814
815         copy( $inpath, $outpath );
816         chmod( ( stat $inpath)[2] , $outpath );
817         return;
818     }
819
820
821     # Set the path to the top from this current file
822     my $updir = dirname( $out_file ) eq '.'
823                 ? '.'
824                 : File::Spec->catdir(  map { '..' } File::Spec->splitdir( dirname($out_file)));
825
826
827     # So we can have relative paths to the toplevel dir
828     my %vars = (
829         rooturl     => $updir, # This is the prefix to get to the top-level
830         self        => $self,  # so cgi script know INCLUDE_PATH and dest_dir
831     );
832     my $vars = { %vars, %$options };
833
834     $vars->{this}{file} = $out_file;
835
836
837
838
839     my $capture = '';
840     my $output = $self->config->dryrun ? \$capture : $out_file;
841
842
843     $self->template->process( $in_file, $vars, $output ) || warn  $self->template->error . "\n";
844
845
846     $self->logfile('Process', $in_file, length $capture || (stat $outpath)[7]);
847     return 1 if $self->config->dryrun;
848
849     $main::exit_value = 0;
850
851     my $mode = $options->{mode} || ( stat $inpath)[2];
852
853     chmod( $mode , $outpath );
854
855     return 1;  # return true if processed a file
856
857 }
858
859
860 #=======================================================================
861 # Find a relative file in INCLUDE_PATH and return it.
862 #-----------------------------------------------------------------------
863
864 sub find_in_include {
865     my ( $self, $file ) = @_;
866
867     for my $dir ( @{$self->include_path} ) {
868         my $path = File::Spec->rel2abs( $file, $dir );
869         warn "Looking for [$path]\n" if $self->config->debug;
870         return $path if -f $path;
871     }
872     return;
873 }
874
875
876
877 #----------------------------------------------
878 # Compare to file dates
879
880 sub is_newer {
881     my ( $self, $in_file, $out_file ) = @_;
882     # Check for newer file
883     if ( !$self->config->all && !newer( $in_file, $out_file ) ) {
884         warn "Skipping $in_file is not newer than $out_file\n" if $self->config->debug;
885         return;
886     }
887     return 1;
888
889 }
890 sub newer {
891     my ( $source, $dest ) = @_;
892
893     my $source_date = ( stat $source )[9] || 0;
894     my $dest_date = ( stat $dest)[9] || 0;
895
896     return $source_date > $dest_date;
897 }
898
899
900
901
902 package LoadConfig;
903 use warnings;
904 use strict;
905 use Getopt::Long;
906 use File::Basename;
907
908 sub new {
909     my ( $class, $config, $options ) = @_;
910
911     GetOptions( $config, @$options ) || die "Error parsing options\n";
912
913     my $self = bless $config, $class;
914
915     # Create accessors
916     #
917     no strict 'refs';
918     for (@$options ) {
919         next unless /(^[a-zA-Z_]+)/;
920         my $method = $1;
921         *{$method} = sub { return shift->{$method} || undef };
922     }
923     return $self;
924 }
925
926 # Return true if matches
927
928 sub test_array {
929     my ( $self, $file, $type ) = @_;
930
931     $file = basename( $file );
932
933     my $array = $self->$type;
934     return 1 unless $array;
935     die "type is not an array" unless ref $array eq 'ARRAY';
936
937     for ( @$array ) {
938         if ( $file =~ /$_/ ) {
939             warn "File [$file] matched $type [$_]\n" if $self->debug;
940             return 1;
941         }
942     }
943
944     return 0;
945 }
946
947 sub test_ignore { shift->test_array( shift, 'ignore' ) };
948 sub test_copy { shift->test_array( shift, 'copy' ) };
949
950
951
952
953
Note: See TracBrowser for help on using the browser.