3 eval 'exec /usr/bin/perl -w -S $0 ${1+"$@"}'
4 if 0; # not running under some shell
5 #========================================================================
10 # Script for processing all directory trees containing templates.
11 # Template files are processed and the output directed to the
12 # relvant file in an output tree. The timestamps of the source and
13 # destination files can then be examined for future invocations
14 # to process only those files that have changed. In other words,
15 # it's a lot like 'make' for templates.
18 # Andy Wardley <abw@wardley.org>
21 # Copyright (C) 1996-2003 Andy Wardley. All Rights Reserved.
22 # Copyright (C) 1998-2003 Canon Research Centre Europe Ltd.
24 # This module is free software; you can redistribute it and/or
25 # modify it under the same terms as Perl itself.
27 #------------------------------------------------------------------------
29 # $Id: ttree 1196 2009-04-07 13:34:14Z abw $
31 #========================================================================
35 use AppConfig qw( :expand );
40 use Text::ParseWords qw(quotewords);
44 my $HOME = $ENV{ HOME } || '';
45 my $RCFILE = $ENV{"\U${NAME}rc"} || "$HOME/.${NAME}rc";
46 my $TTMODULE = 'Template';
48 #------------------------------------------------------------------------
49 # configuration options
50 #------------------------------------------------------------------------
52 # offer create a sample config file if it doesn't exist, unless a '-f'
53 # has been specified on the command line
54 unless (-f $RCFILE or grep(/^(-f|-h|--help)$/, @ARGV) ) {
55 print("Do you want me to create a sample '.ttreerc' file for you?\n",
56 "(file: $RCFILE) [y/n]: ");
58 if ($y =~ /^y(es)?/i) {
59 write_config($RCFILE);
64 # read configuration file and command line arguments - I need to remember
65 # to fix varlist() and varhash() in AppConfig to make this nicer...
66 my $config = read_config($RCFILE);
67 my $dryrun = $config->nothing;
68 my $verbose = $config->verbose || $dryrun;
69 my $colour = $config->colour;
70 my $summary = $config->summary;
71 my $recurse = $config->recurse;
72 my $preserve = $config->preserve;
73 my $all = $config->all;
74 my $libdir = $config->lib;
75 my $ignore = $config->ignore;
76 my $copy = $config->copy;
77 my $accept = $config->accept;
78 my $absolute = $config->absolute;
79 my $relative = $config->relative;
80 my $suffix = $config->suffix;
81 my $binmode = $config->binmode;
82 my $depends = $config->depend;
83 my $depsfile = $config->depend_file;
84 my ($n_proc, $n_unmod, $n_skip, $n_copy, $n_mkdir) = (0) x 5;
86 my $srcdir = $config->src
87 || die "Source directory not set (-s)\n";
88 my $destdir = $config->dest
89 || die "Destination directory not set (-d)\n";
90 die "Source and destination directories may not be the same:\n $srcdir\n"
91 if $srcdir eq $destdir;
93 # unshift any perl5lib directories onto front of INC
94 unshift(@INC, @{ $config->perl5lib });
96 # get all template_* options from the config and fold keys to UPPER CASE
97 my %ttopts = $config->varlist('^template_', 1);
98 my $ttmodule = delete($ttopts{ module });
100 map { my $v = $ttopts{ $_ }; defined $v ? (uc $_, $v) : () }
104 # get all template variable definitions
105 my $replace = $config->get('define');
107 # now create complete parameter hash for creating template processor
110 RELATIVE => $relative,
111 ABSOLUTE => $absolute,
112 INCLUDE_PATH => [ $srcdir, @$libdir ],
113 OUTPUT_PATH => $destdir,
116 # load custom template module
118 my $ttpkg = $ttmodule;
124 $ttmodule = $TTMODULE;
128 #------------------------------------------------------------------------
129 # inter-file dependencies
130 #------------------------------------------------------------------------
132 if ($depsfile or $depends) {
133 $depends = dependencies($depsfile, $depends);
139 my $global_deps = $depends->{'*'} || [ ];
141 # add any PRE_PROCESS, etc., templates as global dependencies
142 foreach my $ttopt (qw( PRE_PROCESS POST_PROCESS PROCESS WRAPPER )) {
143 my $deps = $ucttopts->{ $ttopt } || next;
144 my @deps = ref $deps eq 'ARRAY' ? (@$deps) : ($deps);
146 push(@$global_deps, @deps);
149 # remove any duplicates
150 $global_deps = { map { ($_ => 1) } @$global_deps };
151 $global_deps = [ keys %$global_deps ];
153 # update $depends hash or delete it if there are no dependencies
155 $depends->{'*'} = $global_deps;
158 delete $depends->{'*'};
159 $global_deps = undef;
162 unless keys %$depends;
164 my $DEP_DEBUG = $config->depend_debug();
167 #------------------------------------------------------------------------
169 #------------------------------------------------------------------------
190 print "$NAME $VERSION (Template Toolkit version $Template::VERSION)\n\n";
192 my $sfx = join(', ', map { "$_ => $suffix->{$_}" } keys %$suffix);
194 print(" Source: $srcdir\n",
195 " Destination: $destdir\n",
196 "Include Path: [ @$libdir ]\n",
197 " Ignore: [ @$ignore ]\n",
198 " Copy: [ @$copy ]\n",
199 " Accept: [ @$accept ]\n",
200 " Suffix: [ $sfx ]\n");
201 print(" Module: $ttmodule ", $ttmodule->module_version(), "\n")
202 unless $ttmodule eq $TTMODULE;
204 if ($depends && $DEP_DEBUG) {
205 print "Dependencies:\n";
206 foreach my $key ('*', grep { !/\*/ } keys %$depends) {
207 printf( " %-16s %s\n", $key,
208 join(', ', @{ $depends->{ $key } }) )
209 if defined $depends->{ $key };
213 print "\n" if $verbose > 1;
214 print red("NOTE: dry run, doing nothing...\n")
218 #------------------------------------------------------------------------
219 # main processing loop
220 #------------------------------------------------------------------------
222 my $template = $ttmodule->new($ttopts)
223 || die $ttmodule->error();
226 # explicitly process files specified on command lines
227 foreach my $file (@ARGV) {
228 my $path = $srcdir ? File::Spec->catfile($srcdir, $file) : $file;
233 process_file($file, $path, force => 1);
238 # implicitly process all file in source directory
242 if ($summary || $verbose) {
243 my $format = "%13d %s %s\n";
244 print "\n" if $verbose > 1;
247 $dryrun ? red("This was a dry run. Nothing was actually done\n") : "\n",
248 green(sprintf($format, $n_proc, $n_proc == 1 ? 'file' : 'files', 'processed')),
249 green(sprintf($format, $n_copy, $n_copy == 1 ? 'file' : 'files', 'copied')),
250 green(sprintf($format, $n_mkdir, $n_mkdir == 1 ? 'directory' : 'directories', 'created')),
251 yellow(sprintf($format, $n_unmod, $n_unmod == 1 ? 'file' : 'files', 'skipped (not modified)')),
252 yellow(sprintf($format, $n_skip, $n_skip == 1 ? 'file' : 'files', 'skipped (ignored)'))
259 #========================================================================
261 #========================================================================
264 #------------------------------------------------------------------------
267 # Walks the directory tree starting at $dir or the current directory
268 # if unspecified, processing files as found.
269 #------------------------------------------------------------------------
273 my ($file, $path, $abspath, $check);
277 my $absdir = join('/', $srcdir ? $srcdir : (), defined $dir ? $dir : ());
280 opendir(DIR, $absdir) || do { warn "$absdir: $!\n"; return undef; };
282 FILE: while (defined ($file = readdir(DIR))) {
283 next if $file eq '.' || $file eq '..';
284 $path = defined $dir ? "$dir/$file" : $file;
285 $abspath = "$absdir/$file";
287 next unless -e $abspath;
289 # check against ignore list
290 foreach $check (@$ignore) {
291 if ($path =~ /$check/) {
292 printf yellow(" - %-32s (ignored, matches /$check/)\n"), $path
299 # check against acceptance list
301 unless ((-d $abspath && $recurse) || grep { $path =~ /$_/ } @$accept) {
302 printf yellow(" - %-32s (not accepted)\n"), $path
311 my ($uid, $gid, $mode);
313 (undef, undef, $mode, undef, $uid, $gid, undef, undef,
314 undef, undef, undef, undef, undef) = stat($abspath);
316 # create target directory if required
317 $target = "$destdir/$path";
318 unless (-d $target || $dryrun) {
319 mkpath($target, $verbose, $mode) or
320 die red("Could not mkpath ($target): $!\n");
322 # commented out by abw on 2000/12/04 - seems to raise a warning?
323 # chown($uid, $gid, $target) || warn "chown($target): $!\n";
326 printf green(" + %-32s (created target directory)\n"), $path
329 # recurse into directory
334 printf yellow(" - %-32s (directory, not recursing)\n"), $path
339 process_file($path, $abspath);
346 #------------------------------------------------------------------------
349 # File filtering and processing sub-routine called by process_tree()
350 #------------------------------------------------------------------------
353 my ($file, $absfile, %options) = @_;
354 my ($dest, $destfile, $filename, $check,
355 $srctime, $desttime, $mode, $uid, $gid);
356 my ($old_suffix, $new_suffix);
361 $filename = basename($file);
364 # look for any relevant suffix mapping
366 if ($filename =~ m/\.(.+)$/) {
368 if ($new_suffix = $suffix->{ $old_suffix }) {
369 $destfile =~ s/$old_suffix$/$new_suffix/;
373 $dest = $destdir ? "$destdir/$destfile" : $destfile;
375 # print "proc $file => $dest\n";
377 # check against copy list
378 foreach my $copy_pattern (@$copy) {
379 if ($filename =~ /$copy_pattern/) {
381 $check = $copy_pattern;
386 # stat the source file unconditionally, so we can preserve
388 ( undef, undef, $mode, undef, $uid, $gid, undef,
389 undef, undef, $srctime, undef, undef, undef ) = stat($absfile);
391 # test modification time of existing destination file
392 if (! $all && ! $options{ force } && -f $dest) {
393 $desttime = ( stat($dest) )[9];
395 if (defined $depends and not $copy_file) {
396 my $deptime = depend_time($file, $depends);
397 if (defined $deptime && ($srctime < $deptime)) {
403 if ($desttime >= $srctime) {
404 printf yellow(" - %-32s (not modified)\n"), $file
411 # check against copy list
415 copy($absfile, $dest) or die red("Could not copy ($absfile to $dest) : $!\n");
418 chown($uid, $gid, $dest) || warn red("chown($dest): $!\n");
419 chmod($mode, $dest) || warn red("chmod($dest): $!\n");
423 printf green(" > %-32s (copied, matches /$check/)\n"), $file
432 printf(green(" + %-32s"), $file);
433 print(green(" (changed suffix to $new_suffix)")) if $new_suffix;
439 $template->process($file, $replace, $destfile,
440 $binmode ? {binmode => $binmode} : {})
441 || print(red(" ! "), $template->error(), "\n");
444 chown($uid, $gid, $dest) || warn red("chown($dest): $!\n");
445 chmod($mode, $dest) || warn red("chmod($dest): $!\n");
451 #------------------------------------------------------------------------
452 # dependencies($file, $depends)
454 # Read the dependencies from $file, if defined, and merge in with
455 # those passed in as the hash array $depends, if defined.
456 #------------------------------------------------------------------------
459 my ($file, $depend) = @_;
463 my ($fh, $text, $line);
464 open $fh, $file or die "Can't open $file, $!";
468 $text =~ s[\\\n][]mg;
470 foreach $line (split("\n", $text)) {
471 next if $line =~ /^\s*(#|$)/;
473 my ($file, @files) = quotewords('\s*:\s*', 0, $line);
475 @files = grep(defined, quotewords('(,|\s)\s*', 0, @files));
476 $depends{$file} = \@files;
480 if (defined $depend) {
481 foreach my $key (keys %$depend) {
482 $depends{$key} = [ quotewords(',', 0, $depend->{$key}) ];
491 #------------------------------------------------------------------------
492 # depend_time($file, \%depends)
494 # Returns the mtime of the most recent in @files.
495 #------------------------------------------------------------------------
498 my ($file, $depends) = @_;
499 my ($deps, $absfile, $modtime);
501 my @pending = ($file);
505 # push any global dependencies onto the pending list
506 if ($deps = $depends->{'*'}) {
507 push(@pending, @$deps);
510 print " # checking dependencies for $file...\n"
513 # iterate through the list of pending files
515 $file = shift @pending;
516 next if $seen{ $file }++;
518 if (File::Spec->file_name_is_absolute($file) && -f $file) {
519 $modtime = (stat($file))[9];
520 print " # $file [$modtime]\n"
525 foreach my $dir ($srcdir, @$libdir) {
526 $absfile = File::Spec->catfile($dir, $file);
528 $modtime = (stat($absfile))[9];
529 print " # $absfile [$modtime]\n"
536 if $modtime > $maxtime;
538 if ($deps = $depends->{ $file }) {
539 push(@pending, @$deps);
540 print " # depends on ", join(', ', @$deps), "\n"
549 #------------------------------------------------------------------------
552 # Handles reading of config file and/or command line arguments.
553 #------------------------------------------------------------------------
559 my ($state, $var, $value) = @_;
560 $state->{ VARIABLE }->{ verbose } = $value ? ++$verbose : --$verbose;
562 my $config = AppConfig->new(
564 ERROR => sub { die(@_, "\ntry `$NAME --help'\n") }
566 'help|h' => { ACTION => \&help },
567 'src|s=s' => { EXPAND => EXPAND_ALL },
568 'dest|d=s' => { EXPAND => EXPAND_ALL },
569 'lib|l=s@' => { EXPAND => EXPAND_ALL },
570 'cfg|c=s' => { EXPAND => EXPAND_ALL, DEFAULT => '.' },
571 'verbose|v' => { DEFAULT => 0, ACTION => $verbinc },
572 'recurse|r' => { DEFAULT => 0 },
573 'nothing|n' => { DEFAULT => 0 },
574 'preserve|p' => { DEFAULT => 0 },
575 'absolute' => { DEFAULT => 0 },
576 'relative' => { DEFAULT => 0 },
577 'colour|color'=> { DEFAULT => 0 },
578 'summary' => { DEFAULT => 0 },
579 'all|a' => { DEFAULT => 0 },
587 'depend_debug|depdbg',
588 'depend_file|depfile=s' => { EXPAND => EXPAND_ALL },
589 'template_module|module=s',
590 'template_anycase|anycase',
591 'template_encoding|encoding=s',
592 'template_eval_perl|eval_perl',
593 'template_load_perl|load_perl',
594 'template_interpolate|interpolate',
595 'template_pre_chomp|pre_chomp|prechomp',
596 'template_post_chomp|post_chomp|postchomp',
597 'template_trim|trim',
598 'template_pre_process|pre_process|preprocess=s@',
599 'template_post_process|post_process|postprocess=s@',
600 'template_process|process=s',
601 'template_wrapper|wrapper=s',
602 'template_recursion|recursion',
603 'template_expose_blocks|expose_blocks',
604 'template_default|default=s',
605 'template_error|error=s',
606 'template_debug|debug=s',
607 'template_start_tag|start_tag|starttag=s',
608 'template_end_tag|end_tag|endtag=s',
609 'template_tag_style|tag_style|tagstyle=s',
610 'template_compile_ext|compile_ext=s',
611 'template_compile_dir|compile_dir=s' => { EXPAND => EXPAND_ALL },
612 'template_plugin_base|plugin_base|pluginbase=s@' => { EXPAND => EXPAND_ALL },
613 'perl5lib|perllib=s@' => { EXPAND => EXPAND_ALL },
616 # add the 'file' option now that we have a $config object that we
617 # can reference in a closure
620 EXPAND => EXPAND_ALL,
622 my ($state, $item, $file) = @_;
623 $file = $state->cfg . "/$file"
624 unless $file =~ /^[\.\/]|(?:\w:)/;
625 $config->file($file) }
629 # process main config file, then command line args
630 $config->file($file) if -f $file;
639 my $text = join('', @_);
642 # look for an existing escape start sequence and add new
643 # attribute to it, otherwise add escape start/end sequences
644 s/ \e \[ ([1-9][\d;]*) m/\e[$1;${attr}m/gx
646 : "\e[${attr}m" . $_ . "\e[0m";
648 split(/\n/, $text, -1) # -1 prevents it from ignoring trailing fields
652 sub _red(@) { ANSI_escape(31, @_) }
653 sub _green(@) { ANSI_escape(32, @_) }
654 sub _yellow(@) { ANSI_escape(33, @_) }
655 sub _blue(@) { ANSI_escape(34, @_) }
656 sub _white(@) { @_ } # nullop
659 #------------------------------------------------------------------------
660 # write_config($file)
662 # Writes a sample configuration file to the filename specified.
663 #------------------------------------------------------------------------
668 open(CONFIG, ">$file") || die "failed to create $file: $!\n";
669 print(CONFIG <<END_OF_CONFIG);
670 #------------------------------------------------------------------------
671 # sample .ttreerc file created automatically by $NAME version $VERSION
673 # This file originally written to $file
675 # For more information on the contents of this configuration file, see
680 #------------------------------------------------------------------------
682 # The most flexible way to use ttree is to create a separate directory
683 # for configuration files and simply use the .ttreerc to tell ttree where
686 # cfg = /path/to/ttree/config/directory
688 # print summary of what's going on
691 # recurse into any sub-directories and process files
694 # regexen of things that aren't templates and should be ignored
695 ignore = \\b(CVS|RCS)\\b
698 # ditto for things that should be copied rather than processed.
702 # by default, everything not ignored or copied is accepted; add 'accept'
703 # lines if you want to filter further. e.g.
708 # options to rewrite files suffixes (htm => html, tt2 => html)
713 # options to define dependencies between templates
715 # depend *=header,footer,menu
716 # depend index.html=mainpage,sidebar
717 # depend menu=menuitem,menubar
720 #------------------------------------------------------------------------
721 # The following options usually relate to a particular project so
722 # you'll probably want to put them in a separate configuration file
723 # in the directory specified by the 'cfg' option and then invoke tree
724 # using '-f' to tell it which configuration you want to use.
725 # However, there's nothing to stop you from adding default 'src',
726 # 'dest' or 'lib' options in the .ttreerc. The 'src' and 'dest' options
727 # can be re-defined in another configuration file, but be aware that 'lib'
728 # options accumulate so any 'lib' options defined in the .ttreerc will
729 # be applied every time you run ttree.
730 #------------------------------------------------------------------------
731 # # directory containing source page templates
732 # src = /path/to/your/source/page/templates
734 # # directory where output files should be written
735 # dest = /path/to/your/html/output/directory
737 # # additional directories of library templates
738 # lib = /first/path/to/your/library/templates
739 # lib = /second/path/to/your/library/templates
744 print "$file created. Please edit accordingly and re-run $NAME\n";
748 #------------------------------------------------------------------------
751 # Prints help message and exits.
752 #------------------------------------------------------------------------
756 $NAME $VERSION (Template Toolkit version $Template::VERSION)
758 usage: $NAME [options] [files]
761 -a (--all) Process all files, regardless of modification
762 -r (--recurse) Recurse into sub-directories
763 -p (--preserve) Preserve file ownership and permission
764 -n (--nothing) Do nothing, just print summary (enables -v)
765 -v (--verbose) Verbose mode. Use twice for more verbosity: -v -v
766 -h (--help) This help
767 -s DIR (--src=DIR) Source directory
768 -d DIR (--dest=DIR) Destination directory
769 -c DIR (--cfg=DIR) Location of configuration files
770 -l DIR (--lib=DIR) Library directory (INCLUDE_PATH) (multiple)
771 -f FILE (--file=FILE) Read named configuration file (multiple)
774 --colour / --color Enable colo(u)rful verbose output.
775 --summary Show processing summary.
777 File search specifications (all may appear multiple times):
778 --ignore=REGEX Ignore files matching REGEX
779 --copy=REGEX Copy files matching REGEX
780 --accept=REGEX Process only files matching REGEX
782 File Dependencies Options:
783 --depend foo=bar,baz Specify that 'foo' depends on 'bar' and 'baz'.
784 --depend_file FILE Read file dependancies from FILE.
785 --depend_debug Enable debugging for dependencies
787 File suffix rewriting (may appear multiple times)
788 --suffix old=new Change any '.old' suffix to '.new'
790 File encoding options
791 --binmode=value Set binary mode of output files
792 --encoding=value Set encoding of input files
794 Additional options to set Template Toolkit configuration items:
795 --define var=value Define template variable
796 --interpolate Interpolate '\$var' references in text
797 --anycase Accept directive keywords in any case.
798 --pre_chomp Chomp leading whitespace
799 --post_chomp Chomp trailing whitespace
800 --trim Trim blank lines around template blocks
801 --eval_perl Evaluate [% PERL %] ... [% END %] code blocks
802 --load_perl Load regular Perl modules via USE directive
803 --absolute Enable the ABSOLUTE option
804 --relative Enable the RELATIVE option
805 --pre_process=TEMPLATE Process TEMPLATE before each main template
806 --post_process=TEMPLATE Process TEMPLATE after each main template
807 --process=TEMPLATE Process TEMPLATE instead of main template
808 --wrapper=TEMPLATE Process TEMPLATE wrapper around main template
809 --default=TEMPLATE Use TEMPLATE as default
810 --error=TEMPLATE Use TEMPLATE to handle errors
811 --debug=STRING Set TT DEBUG option to STRING
812 --start_tag=STRING STRING defines start of directive tag
813 --end_tag=STRING STRING defined end of directive tag
814 --tag_style=STYLE Use pre-defined tag STYLE
815 --plugin_base=PACKAGE Base PACKAGE for plugins
816 --compile_ext=STRING File extension for compiled template files
817 --compile_dir=DIR Directory for compiled template files
818 --perl5lib=DIR Specify additional Perl library directories
819 --template_module=MODULE Specify alternate Template module
821 See 'perldoc ttree' for further information.
831 #------------------------------------------------------------------------
833 # This documentation is generated automatically from source
834 # templates. Any changes you make here may be lost.
836 # The 'docsrc' documentation source bundle is available for download
837 # from http://www.template-toolkit.org/docs.html and contains all
838 # the source templates, XML files, scripts, etc., from which the
839 # documentation for the Template Toolkit is built.
840 #------------------------------------------------------------------------
844 Template::Tools::ttree - Process entire directory trees of templates
848 ttree [options] [files]
852 The F<ttree> script is used to process entire directory trees containing
853 template files. The resulting output from processing each file is then
854 written to a corresponding file in a destination directory. The script
855 compares the modification times of source and destination files (where
856 they already exist) and processes only those files that have been modified.
857 In other words, it is the equivalent of 'make' for the Template Toolkit.
859 It supports a number of options which can be used to configure
860 behaviour, define locations and set Template Toolkit options. The
861 script first reads the F<.ttreerc> configuration file in the HOME
862 directory, or an alternative file specified in the TTREERC environment
863 variable. Then, it processes any command line arguments, including
864 any additional configuration files specified via the C<-f> (file)
867 =head2 The F<.ttreerc> Configuration File
869 When you run F<ttree> for the first time it will ask you if you want
870 it to create a F<.ttreerc> file for you. This will be created in your
874 Do you want me to create a sample '.ttreerc' file for you?
875 (file: /home/abw/.ttreerc) [y/n]: y
876 /home/abw/.ttreerc created. Please edit accordingly and re-run ttree
878 The purpose of this file is to set any I<global> configuration options
879 that you want applied I<every> time F<ttree> is run. For example, you
880 can use the C<ignore> and C<copy> option to provide regular expressions
881 that specify which files should be ignored and which should be copied
882 rather than being processed as templates. You may also want to set
883 flags like C<verbose> and C<recurse> according to your preference.
885 A minimal F<.ttreerc>:
888 ignore = \b(CVS|RCS)\b
893 copy = \.(gif|png|jpg|pdf)$
895 # recurse into directories
898 # provide info about what's going on
901 In most cases, you'll want to create a different F<ttree> configuration
902 file for each project you're working on. The C<cfg> option allows you
903 to specify a directory where F<ttree> can find further configuration
906 cfg = /home/abw/.ttree
908 The C<-f> command line option can be used to specify which configuration
909 file should be used. You can specify a filename using an absolute or
912 $ ttree -f /home/abw/web/example/etc/ttree.cfg
913 $ ttree -f ./etc/ttree.cfg
914 $ ttree -f ../etc/ttree.cfg
916 If the configuration file does not begin with C</> or C<.> or something
917 that looks like a MS-DOS absolute path (e.g. C<C:\\etc\\ttree.cfg>) then
918 F<ttree> will look for it in the directory specified by the C<cfg> option.
920 $ ttree -f test1 # /home/abw/.ttree/test1
922 The C<cfg> option can only be used in the F<.ttreerc> file. All the
923 other options can be used in the F<.ttreerc> or any other F<ttree>
924 configuration file. They can all also be specified as command line
927 Remember that F<.ttreerc> is always processed I<before> any
928 configuration file specified with the C<-f> option. Certain options
929 like C<lib> can be used any number of times and accumulate their values.
931 For example, consider the following configuration files:
933 F</home/abw/.ttreerc>:
935 cfg = /home/abw/.ttree
936 lib = /usr/local/tt2/templates
938 F</home/abw/.ttree/myconfig>:
940 lib = /home/abw/web/example/templates/lib
942 When F<ttree> is invoked as follows:
946 the C<lib> option will be set to the following directories:
948 /usr/local/tt2/templates
949 /home/abw/web/example/templates/lib
951 Any templates located under F</usr/local/tt2/templates> will be used
952 in preference to those located under
953 F</home/abw/web/example/templates/lib>. This may be what you want,
954 but then again, it might not. For this reason, it is good practice to
955 keep the F<.ttreerc> as simple as possible and use different
956 configuration files for each F<ttree> project.
958 =head2 Directory Options
960 The C<src> option is used to define the directory containing the
961 source templates to be processed. It can be provided as a command
962 line option or in a configuration file as shown here:
964 src = /home/abw/web/example/templates/src
966 Each template in this directory typically corresponds to a single
967 web page or other document.
969 The C<dest> option is used to specify the destination directory for the
972 dest = /home/abw/web/example/html
974 The C<lib> option is used to define one or more directories containing
975 additional library templates. These templates are not documents in
976 their own right and typically comprise of smaller, modular components
977 like headers, footers and menus that are incorporated into pages templates.
979 lib = /home/abw/web/example/templates/lib
980 lib = /usr/local/tt2/templates
982 The C<lib> option can be used repeatedly to add further directories to
985 A list of templates can be passed to F<ttree> as command line arguments.
987 $ ttree foo.html bar.html
989 It looks for these templates in the C<src> directory and processes them
990 through the Template Toolkit, using any additional template components
991 from the C<lib> directories. The generated output is then written to
992 the corresponding file in the C<dest> directory.
994 If F<ttree> is invoked without explicitly specifying any templates
995 to be processed then it will process every file in the C<src> directory.
996 If the C<-r> (recurse) option is set then it will additionally iterate
997 down through sub-directories and process and other template files it finds
1002 If a template has been processed previously, F<ttree> will compare the
1003 modification times of the source and destination files. If the source
1004 template (or one it is dependant on) has not been modified more
1005 recently than the generated output file then F<ttree> will not process
1006 it. The F<-a> (all) option can be used to force F<ttree> to process
1007 all files regardless of modification time.
1011 Any templates explicitly named as command line argument are always
1012 processed and the modification time checking is bypassed.
1016 The C<ignore>, C<copy> and C<accept> options are used to specify Perl
1017 regexen to filter file names. Files that match any of the C<ignore>
1018 options will not be processed. Remaining files that match any of the
1019 C<copy> regexen will be copied to the destination directory. Remaining
1020 files that then match any of the C<accept> criteria are then processed
1021 via the Template Toolkit. If no C<accept> parameter is specified then
1022 all files will be accepted for processing if not already copied or
1025 # ignore these files
1026 ignore = \b(CVS|RCS)\b
1031 copy = \.(gif|png|jpg|pdf)$
1033 # accept only .tt2 templates
1036 The C<suffix> option is used to define mappings between the file
1037 extensions for source templates and the generated output files. The
1038 following example specifies that source templates with a C<.tt2>
1039 suffix should be output as C<.html> files:
1043 Or on the command line,
1047 You can provide any number of different suffix mappings by repeating
1050 The C<binmode> option is used to set the encoding of the output file.
1051 For example use C<--binmode=:utf8> to set the output format to unicode.
1053 =head2 Template Dependencies
1055 The C<depend> and C<depend_file> options allow you to specify
1056 how any given template file depends on another file or group of files.
1057 The C<depend> option is used to express a single dependency.
1059 $ ttree --depend foo=bar,baz
1061 This command line example shows the C<--depend> option being used to
1062 specify that the F<foo> file is dependant on the F<bar> and F<baz>
1063 templates. This option can be used many time on the command line:
1065 $ ttree --depend foo=bar,baz --depend crash=bang,wallop
1067 or in a configuration file:
1070 depend crash=bang,wallop
1072 The file appearing on the left of the C<=> is specified relative to
1073 the C<src> or C<lib> directories. The file(s) appearing on the right
1074 can be specified relative to any of these directories or as absolute
1079 $ ttree --depend foo=bar,/tmp/baz
1081 To define a dependency that applies to all files, use C<*> on the
1084 $ ttree --depend *=header,footer
1086 or in a configuration file:
1088 depend *=header,footer
1090 Any templates that are defined in the C<pre_process>, C<post_process>,
1091 C<process> or C<wrapper> options will automatically be added to the
1092 list of global dependencies that apply to all templates.
1094 The C<depend_file> option can be used to specify a file that contains
1095 dependency information.
1097 $ ttree --depend_file=/home/abw/web/example/etc/ttree.dep
1099 Here is an example of a dependency file:
1101 # This is a comment. It is ignored.
1103 index.html: header footer menubar
1105 header: titlebar hotlinks
1109 # spanning multiple lines with the backslash
1110 another.html: header footer menubar \
1113 Lines beginning with the C<#> character are comments and are ignored.
1114 Blank lines are also ignored. All other lines should provide a
1115 filename followed by a colon and then a list of dependant files
1116 separated by whitespace, commas or both. Whitespace around the colon
1117 is also optional. Lines ending in the C<\> character are continued
1118 onto the following line.
1120 Files that contain spaces can be quoted. That is only necessary
1121 for files after the colon (':'). The file before the colon may be
1122 quoted if it contains a colon.
1124 As with the command line options, the C<*> character can be used
1125 as a wildcard to specify a dependency for all templates.
1129 =head2 Template Toolkit Options
1131 F<ttree> also provides access to the usual range of Template Toolkit
1132 options. For example, the C<--pre_chomp> and C<--post_chomp> F<ttree>
1133 options correspond to the C<PRE_CHOMP> and C<POST_CHOMP> options.
1135 Run C<ttree -h> for a summary of the options available.
1139 Andy Wardley E<lt>abw@andywardley.comE<gt>
1141 L<http://www.andywardley.com/|http://www.andywardley.com/>
1143 With contributions from Dylan William Hardison (support for
1144 dependencies), Bryce Harrington (C<absolute> and C<relative> options),
1145 Mark Anderson (C<suffix> and C<debug> options), Harald Joerg and Leon
1146 Brocard who gets everywhere, it seems.
1150 2.68, distributed as part of the
1151 Template Toolkit version 2.19, released on 27 April 2007.
1155 Copyright (C) 1996-2007 Andy Wardley. All Rights Reserved.
1158 This module is free software; you can redistribute it and/or
1159 modify it under the same terms as Perl itself.
1163 L<tpage|Template::Tools::tpage>