root/trunk/build/theme-builder.pl @ 3531

Revision 3531, 8.2 kB (checked in by fumiakiy, 9 months ago)

Merged sockfish to trunk. "svn merge -r3114:3527 http://code.sixapart.com/svn/movabletype/branches/sockfish/ ."

  • Property svn:executable set to *
  • Property svn:keywords set to Id Revision
Line 
1#!/usr/bin/perl
2
3# Movable Type (r) Open Source (C) 2001-2009 Six Apart, Ltd.
4# This program is distributed under the terms of the
5# GNU General Public License, version 2.
6#
7# $Id$
8
9use strict;
10use warnings;
11
12use FindBin qw( $Bin );
13use lib "$Bin/../../cpan-lib";
14
15use Pod::Usage;
16use Template;
17use YAML;
18use File::Spec::Functions qw/catfile file_name_is_absolute abs2rel splitdir/;
19use File::Basename;
20use Getopt::Long;
21Getopt::Long::Configure('no_ignore_case');
22use Data::Dumper;
23use File::Find;
24
25use Template::Constants ':chomp';
26
27
28my ($version, $help, $man, $VERBOSE, $app);
29
30GetOptions (
31             'h|help'          => \$help,
32             'm|man'           => \$man,
33             'v|verbose'       => \$VERBOSE,
34             'app=s'           => \$app,
35           );
36$man and pod2usage(-verbose => 2);
37$help and pod2usage;
38
39$app ||= 'archetype';
40
41my $themedir = "$Bin/../mt-static/themes";
42my $templatedir = "$Bin/theme_templates/auto";
43my $modulesdir = "$Bin/theme_templates/modules";
44
45foreach ($themedir, $templatedir) {
46    s|archetype/tools/../../$app|$app|;
47}
48
49## Set up a global TT object. (Global so that it maintains a cache.)
50our $Template = Template->new({
51    INCLUDE_PATH => $modulesdir, 
52    ABSOLUTE => 1,
53    PRE_CHOMP  => CHOMP_COLLAPSE,
54    POST_CHOMP => CHOMP_NONE,
55    TRIM => 1,
56});
57
58# find all the templates we're going to work from
59my @templates = &find_templates;
60
61# set up all the themes we need to put out
62my @themes_todo = @ARGV;
63if (! @themes_todo) {
64    my $max_tmpl_module_age = &find_max_tmpl_module_age;
65    @themes_todo = &find_themes_needing_regeneration($max_tmpl_module_age, @templates);
66}
67@themes_todo = &names2paths(@themes_todo);   
68
69
70# do the work
71foreach my $theme (@themes_todo) {
72
73    &regenerate($theme);
74}
75
76sub regenerate {
77    my $theme = shift;
78
79    logg("regenerating ".abs2rel($theme));
80
81    my $yaml = load_yamls($theme);
82   
83    foreach my $tt (@templates) {
84
85        debug("making ".abs2rel($tt));
86   
87        my ($name,$path) = fileparse($theme);
88        my $outfile = catfile($path, basename($tt));
89        $outfile =~ s/\.tt$//;
90
91        debug("writing to ".abs2rel($outfile));
92
93#        if (-e $outfile && ! $nobackup) {
94#            my  ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) =
95#                                                               localtime(time);
96#            my $today = sprintf("%4.4d%2.2d%2.2d-%2.2d%2.2d%2.2d", $year+1900, $mon+1, $mday, $hour, $min, $sec);
97#            debug ("saving $outfile as $outfile.$today.bak");
98#            rename $outfile, "$outfile.$today.bak";
99#        }
100
101        my $files_present = find_files_present(dirname($theme));
102
103        $yaml->{find_file} = sub { return $files_present->{$_[0]}};
104
105        $Template->process($tt, {theme => $yaml}, $outfile) || die $Template->error;
106    }
107
108}
109
110sub find_files_present {
111    my ($basedir, $yaml) = @_;
112
113    my $files_present = {};
114
115    opendir (DIR, $basedir) || die "can't opendir $basedir $!";
116    while (my $file = readdir(DIR)) {
117        next unless -f "$basedir/$file";
118        next if $file =~ /\.bak$/;
119
120        $files_present->{$file} = $file;
121
122        my ($shortname, $path, $suffix) = fileparse($file, qw/.gif .png .jpg/);
123
124        #both bg-header.gif and bg-header.jpg exist, save the first one alphabetically
125
126        if ($files_present->{$shortname}) {
127            if ($file lt $files_present->{$shortname}) {
128                $files_present->{$shortname} = $file;
129            }
130        }else{
131            $files_present->{$shortname} = $file;       
132        }
133
134       
135    }
136    closedir DIR;
137
138    return $files_present;
139}
140
141sub load_yamls {
142    my $theme_yaml = shift;
143    $theme_yaml = YAML::LoadFile($theme_yaml);
144    return $theme_yaml;
145}
146
147
148sub logg {
149    my $msg = shift;
150    print "$msg\n";
151}
152
153sub debug {
154    my $msg = shift;
155    print "$msg\n" if $VERBOSE;
156}
157
158sub find_templates {
159    my @templates;
160    opendir (DIR, $templatedir) || die "can't opendir $templatedir $!";
161    while (my $file = readdir(DIR)) {
162        next if -d $file;
163        next if $file =~ /^\./;
164        next unless $file =~ /\.tt$/;
165        push @templates, catfile($templatedir, $file);
166    }
167    closedir DIR;
168    return @templates;
169}
170
171sub find_themes_needing_regeneration {
172    my ($max_tmpl_module_age, @templates) = @_;
173# first look at the data files
174    my (@yamls, %yamlage, %themes_todo, @themes_todo);
175    opendir(DIR, "$themedir") || die "can't open $themedir $!";
176    while (my $theme = readdir(DIR)) {
177       
178        next unless -d catfile($themedir, $theme);
179        next if $theme =~ /^\./;
180        next unless -f catfile($themedir, $theme, 'theme.yaml');
181
182        push @yamls, $theme;
183        $yamlage{$theme} = (stat(catfile($themedir, $theme, 'theme.yaml')))[9];
184        debug("theme.yaml found for $theme, will check age");
185    }
186    closedir DIR;
187
188    # now look each of the templates
189    foreach my $templatefile (@templates) {
190        (my $css_file = basename($templatefile)) =~ s/\.tt$//;
191        my $templateage = (stat($templatefile))[9];
192
193        # the templates lead back to an output file for each
194        # data file that we loaded
195        foreach my $theme (@yamls) {
196
197            # if either the template or the data is newer than
198            # the output, then regenerate the output
199            my $css_age = (stat(catfile($themedir, $theme, $css_file)))[9] || 0;
200            if (   $templateage     > $css_age #template has changed
201                || $yamlage{$theme} > $css_age #data has changed
202                || $max_tmpl_module_age > $css_age #a .tt module has changed
203                ) { 
204                $themes_todo{$theme} = 1;
205                debug("$theme needs to be regenerated");
206                next;
207            }
208        }
209    }
210    @themes_todo = map{$_} sort keys %themes_todo;
211
212    return @themes_todo;
213}
214
215# heavily DWIM
216sub names2paths {
217    my @themes_todo = @_;
218
219    foreach (@themes_todo) {
220
221        # they gave us the full path, so just run with it
222        if (/\theme.yaml$/) {
223            next if -e;
224
225        # they gave us the path to the directory, but not 'theme.yaml'
226        # at the end, fix it up
227        }elsif (-d){
228            $_ = catfile($_, 'theme.yaml');
229            next if -e;
230
231        # they just gave us the theme name
232        }elsif (-e catfile($themedir, $_, 'theme.yaml')){
233            $_ = catfile($themedir, $_, 'theme.yaml');
234            next if -e;
235        }
236
237        # whatever we tried to figure out isn't there
238
239        die "I can't find $_, sorry\n";
240    }   
241    return @themes_todo;
242}
243
244sub find_max_tmpl_module_age {
245    $BT::max_age = 0;
246
247    find( sub {
248            my $mtime;
249            /\.tt$/ &&
250               (($mtime) = (lstat($_))[9]) &&
251               $mtime > $BT::max_age &&
252                ($BT::max_age = $mtime)
253        },
254        "$templatedir/.." #back up one .. to get out of auto/
255        );
256    return $BT::max_age;
257}
258
259__END__
260==head1 NAME
261
262build-themes.pl - generates themes from a theme.yaml file
263
264=head1 SYNOPSIS
265
266 build-themes.pl [options] [theme1 theme2 ...]
267
268 Options:
269
270   --app <app>   specify the application to use ('vox', 'archetype', etc)
271
272   -v|--verbose  more chatty output
273
274   -h|--help     brief help message
275   -m|--man      full man page
276   -V|--version
277
278
279=head1 EXAMPLES
280
281=over 4
282
283=item build any themes that need to be rebuilt
284
285    build-themes.pl
286
287=item just rebuild a couple specific ones
288
289    build-themes.pl piximix-orange pixipets-cat
290
291=item rebuild one in some funky location
292
293    build-themes.pl /home/kgoess/temp/funkymusic/
294or
295    build-themes.pl ../experiments/funkymusic/theme.yaml
296
297=head1 DESCRIPTION
298
299Builds themes from a theme.yaml file and any .tt template files in
300archetype/templates/themes/auto/*.tt. 
301
302The output files, one for each .tt file, will go into the
303same directory as the theme.yaml.
304
305It tries to be pretty generous about allowing you to specify the
306theme names in different ways.
307
308=head1 Template Toolkit
309
310The data in the yaml file is available to the templates under C<theme>, e.g.
311C<theme.somevalue>. 
312
313Existence of a file in the theme directory can be checked via
314
315    theme.find_file('bg-header.gif')
316
317or without the extension
318
319    theme.find_file('bg-header')
320
321The latter case also returns the alphabetically first file that matches,
322so if bg-header.gif and bg-header.jpg both exist:
323
324    what = theme.find_file('bg-header')  #what is now bg-header.gif
325
326=cut
327
Note: See TracBrowser for help on using the browser.