root/branches/athena/build/theme-builder.pl @ 1092

Revision 1092, 8.1 kB (checked in by hachi, 2 years ago)

Merging release-15 to athena branch. svn merge -r59987:60375 http://svn.sixapart.com/repos/eng/movabletype/branches/release-15 .

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