File Coverage

blib/lib/Rex/Apache/Build.pm
Criterion Covered Total %
statement 27 153 17.6
branch 0 66 0.0
condition 0 7 0.0
subroutine 9 21 42.8
pod 10 11 90.9
total 46 258 17.8


line stmt bran cond sub pod time code
1             #
2             # (c) Jan Gehring
3             #
4             # vim: set ts=2 sw=2 tw=0:
5             # vim: set expandtab:
6              
7             =head1 NAME
8              
9             Rex::Apache::Build - Build your WebApp Package
10              
11             =head1 DESCRIPTION
12              
13             With this module you can prepare your WebApp for deployment.
14              
15             =head1 SYNOPSIS
16              
17             yui_path "./yuicompressor-2.4.6.jar";
18              
19             get_version_from "webapp/lib/MyApp.pm", qr{\$VERSION=([^;]+);};
20              
21             get_version_from "webapp/index.php", qr{\$VERSION=([^;]+);};
22              
23             task "build", sub {
24             sprocketize;
25             sprocketize "app/assets/javascript/*.js",
26             out => "public/js/sprockets.js";
27              
28             coffee;
29             coffee "app/assets/coffee",
30             out => "public/js";
31              
32             sass;
33             sass "app/assets/stylesheets",
34             out => "public/stylesheets";
35              
36             yui;
37             yui compress => "file1.js", "file2.js", "file3.css";
38             yui compress => glob("public/javascript/*.js"), glob("public/css/*.css");
39              
40             build;
41              
42             build "webapp",
43             source => "webapp/",
44             version => "1.0";
45             };
46              
47              
48             =head1 EXPORTED FUNCTIONS
49              
50             =over 4
51              
52             =cut
53              
54             package Rex::Apache::Build;
55              
56             our $VERSION = "0.12.0";
57              
58 1     1   827 use strict;
  1         2  
  1         28  
59 1     1   5 use warnings;
  1         2  
  1         34  
60              
61 1     1   12 use Cwd qw(getcwd);
  1         2  
  1         50  
62 1     1   11 use File::Basename qw(basename);
  1         2  
  1         69  
63              
64             require Exporter;
65 1     1   5 use base qw(Exporter);
  1         1  
  1         80  
66 1     1   6 use vars qw(@EXPORT);
  1         1  
  1         68  
67              
68             @EXPORT = qw(build
69             get_version_from get_version
70             yui yui_path
71             coffee coffee_path
72             sprocketize sprocketize_path
73             sass sass_path);
74              
75 1     1   5 use vars qw($yui_path $coffee_path $sprocketize_path $sass_path $APP_VERSION);
  1         1  
  1         59  
76              
77 1     1   892 use Rex::Commands::Run;
  1         104930  
  1         9  
78 1     1   93 use Rex::Logger;
  1         3  
  1         7  
79              
80             =item yui_path($path_to_yui_compressor)
81              
82             This function sets the path to the yui_compressor. If a relative path is given it will search from the path where the Rexfile is in.
83              
84             =cut
85              
86             sub yui_path {
87 0     0 1   ($yui_path) = @_;
88              
89 0 0         unless ( $yui_path =~ m/^\// ) {
90 0           $yui_path = getcwd() . "/" . $yui_path;
91             }
92             }
93              
94             =item coffee_path($path_to_coffee)
95              
96             This function sets the path to the coffee compiler. If a relative path is given it will search from the path where the Rexfile is in.
97              
98             =cut
99              
100             sub coffee_path {
101 0     0 1   ($coffee_path) = @_;
102              
103 0 0         unless ( $coffee_path =~ m/^\// ) {
104 0           $coffee_path = getcwd() . "/" . $coffee_path;
105             }
106             }
107              
108             =item sprocketize_path($path_to_sprocketize)
109              
110             This function sets the path to the sprocketize compiler. If a relative path is given it will search from the path where the Rexfile is in.
111              
112             =cut
113              
114             sub sprocketize_path {
115 0     0 1   ($sprocketize_path) = @_;
116              
117 0 0         unless ( $sprocketize_path =~ m/^\// ) {
118 0           $sprocketize_path = getcwd() . "/" . $sprocketize_path;
119             }
120             }
121              
122             =item sass_path($path_to_sass)
123              
124             This function sets the path to the sass compiler. If a relative path is given it will search from the path where the Rexfile is in.
125              
126             =cut
127              
128             sub sass_path {
129 0     0 1   ($sass_path) = @_;
130              
131 0 0         unless ( $sass_path =~ m/^\// ) {
132 0           $sass_path = getcwd() . "/" . $sass_path;
133             }
134             }
135              
136             =item yui($action, @files)
137              
138             Run a yui command.
139              
140             task "build", sub {
141             # this will compress the given files
142             yui compress => "file1.js", "file2.js", ...;
143              
144             # yui without any parameters will compress all files in public/javascripts
145             yui;
146             };
147              
148             =cut
149              
150             sub yui {
151 0     0 1   my ( $action, @data ) = @_;
152              
153 0   0       $yui_path ||= "yuicompressor.jar";
154              
155 0 0         unless ( -f $yui_path ) {
156 0           die(
157             "No yuicompressor.jar found. Please download this file and define its location with yui_path '/path/to/yuicompress.jar';"
158             );
159             }
160              
161 0 0         unless ($action) {
162 0           $action = "compress";
163             }
164              
165 0 0         unless (@data) {
166 0           @data = glob("public/javascripts/*.js");
167             }
168              
169 0 0 0       if ( $action eq "compress" || $action eq "-compress" ) {
170 0           my @js_files = grep { !/\.min\.js$/ } grep { /\.js$/i } @data;
  0            
  0            
171 0           my @css_files = grep { !/\.min\.css$/ } grep { /\.css$/i } @data;
  0            
  0            
172              
173 0 0         if (@js_files) {
174 0           Rex::Logger::info("Compressing javascript files");
175 0           for my $file (@js_files) {
176 0           my $new_file = $file;
177 0           $new_file =~ s/\.js$/.min.js/;
178 0           Rex::Logger::debug("Compressing $file -> $new_file");
179 0           run "java -jar $yui_path -o $new_file $file";
180             }
181             }
182              
183 0 0         if (@css_files) {
184 0           Rex::Logger::info("Compressing css files");
185 0           for my $file (@css_files) {
186 0           my $new_file = $file;
187 0           $new_file =~ s/\.css$/.min.css/;
188 0           Rex::Logger::debug("Compressing $file -> $new_file");
189 0           run "java -jar $yui_path -o $new_file $file";
190             }
191             }
192             }
193             else {
194 0           die("Action $action not supported.");
195             }
196             }
197              
198             =item build([$name, %options])
199              
200             This function builds your package. Currently only tar.gz packages are supported.
201              
202             # this will a package of the current directory named after the
203             # directory of the Rexfile and append the version provided by
204             # get_version_from() function
205             # This function builds a tar.gz archive.
206             task "build", sub {
207             build;
208             };
209              
210             # this will build a package of the current directory named "my-web-app" and
211             # append the version provided by get_version_from() function.
212             task "build", sub {
213             build "my-web-app";
214             };
215              
216             # this function will build a package of the directory "html", name it
217             # "my-web-app" and append the version "1.0" to it.
218             task "build", sub {
219             build "my-web-app",
220             path => "html",
221             version => "1.0",
222             exclude => ["yuicompressor.jar", "foobar.html"],
223             type => "tgz";
224             };
225              
226             =cut
227              
228             sub build {
229 0     0 1   my ( $name, %option ) = @_;
230              
231 0 0         unless ($name) {
232 0           $name = basename( getcwd() );
233             }
234              
235 0 0         if ( !%option ) {
236 0 0         if ( Rex::Config->get("package_option") ) {
237 0           %option = %{ Rex::Config->get("package_option") };
  0            
238             }
239             }
240              
241 0 0         if ( !exists $option{version} ) {
242 0           $option{version} = &$APP_VERSION();
243             }
244              
245 0           my $old_dir = getcwd();
246              
247 0   0       my $type = $option{type} || "tgz";
248              
249 0           my $klass = "Rex::Apache::Build::$type";
250 0           eval "use $klass";
251 0 0         if ($@) {
252 0           die("Can't find build class for type: $type");
253             }
254              
255 0           Rex::Logger::debug("Using Buildclass: $klass");
256 0           $option{name} = $name;
257 0           my $build = $klass->new(%option);
258              
259 0           $build->build;
260              
261 0           chdir($old_dir);
262             }
263              
264             =item get_version_from($file, $regexp)
265              
266             Get the version out of a file.
267              
268             =cut
269              
270             sub get_version_from {
271 0     0 1   my ( $file, $regex ) = @_;
272              
273 0 0         if ( ref($file) eq "CODE" ) {
274 0           $APP_VERSION = $file;
275 0           return;
276             }
277              
278             $APP_VERSION = sub {
279              
280 0 0   0     unless ( -f $file ) {
281 0           Rex::Logger::info( "Version file not found ($file). Current Path: "
282             . getcwd()
283             . ". Using current time." );
284 0           return "" . time;
285             }
286              
287             my ($version) =
288 0 0         grep { $_ = $1 if $_ =~ $regex; } eval { local (@ARGV) = ($file); <>; };
  0            
  0            
  0            
289              
290 0           return $version;
291              
292 0           };
293             }
294              
295             sub get_version {
296 0     0 0   return &$APP_VERSION();
297             }
298              
299             =item sprocketize($path_to_js_files, %option)
300              
301             This function calls the sprocketize command with the given options.
302              
303             task "build", sub {
304             sprocketize "app/javascript/*.js",
305             include => [qw|app/javascripts vendor/sprockets/prototype/src|],
306             asset_root => "public/js",
307             out => "public/js/sprockets.js";
308              
309             # to include more use an arrayRef
310             sprocketize ["app/javascript/*.js", "app/javascript/po/*.js"],
311             include => [qw|app/javascripts vendor/sprockets/prototype/src|],
312             asset_root => "public/js",
313             out => "public/js/sprockets.js";
314              
315             # if called without parameters
316              
317             sprocketize;
318              
319             # it will use the following defaults:
320             # - javascript (sprockets) in assets/javascripts/*.js
321             # - include assets/javascripts
322             # - asset_root public
323             # - out public/${name_of_directory_where_Rexfile_lives}.js
324             };
325              
326             =cut
327              
328             sub sprocketize {
329 0     0 1   my ( $files, %option ) = @_;
330              
331 0           my $dirname = basename( getcwd() );
332              
333 0 0         unless ($sprocketize_path) {
334 0           $sprocketize_path = "sprocketize";
335             }
336              
337 0 0         unless ($files) {
338 0           $files = ["assets/javascripts/*.js"];
339             }
340              
341 0 0         if ( !exists $option{out} ) {
342 0           $option{out} = "public/$dirname.js";
343             }
344              
345 0 0         if ( !exists $option{asset_root} ) {
346 0           $option{asset_root} = "public";
347             }
348              
349 0 0         if ( !exists $option{include} ) {
350 0           $option{include} = ["app/javascripts"];
351             }
352              
353 0 0         if ( ref($files) ne "ARRAY" ) {
354 0           $files = [$files];
355             }
356              
357 0           my $files_str = join( " ", @{$files} );
  0            
358 0           my $includes = " -I " . join( " -I ", @{ $option{include} } );
  0            
359              
360 0           Rex::Logger::info("Sprocketizing...");
361             run "$sprocketize_path $includes --asset-root="
362             . $option{asset_root}
363             . " $files_str > "
364 0           . $option{out};
365 0 0         if ( $? == 0 ) {
366 0           Rex::Logger::info("...done.");
367             }
368             else {
369 0           Rex::Logger::info("Error running sprocketize");
370 0           die("Error running sprocketize");
371             }
372             }
373              
374             =item coffee($path, %options)
375              
376             Compile coffee files to javascript.
377              
378             task "build", sub {
379             # this command will build all files in "coffeesrc" and
380             # write the output to "javascripts"
381             coffee "coffeesrc",
382             out => "javascripts";
383              
384             # without parameters it will build all files in assets/coffee
385             # and write the output to public/javascripts.
386             coffee;
387             };
388              
389             =cut
390              
391             sub coffee {
392 0     0 1   my ( $path, %option ) = @_;
393              
394 0 0         unless ($coffee_path) {
395 0           $coffee_path = "coffee";
396             }
397              
398 0 0         unless ($path) {
399 0           $path = "assets/coffee";
400             }
401              
402 0 0         if ( !exists $option{out} ) {
403 0           $option{out} = "public/javascripts";
404             }
405              
406 0           Rex::Logger::info("Building coffee script files...");
407 0           my $ret = run "coffee -o " . $option{out} . " -c " . $path . " 2>&1";
408              
409 0 0         if ( $? == 0 ) {
410 0           Rex::Logger::info("...done.");
411             }
412             else {
413 0           Rex::Logger::info("Error building coffeescripts. $ret");
414 0           die("Error building coffeescripts.");
415             }
416             }
417              
418             =item sass($input_dir, %option)
419              
420             This command will compile all sass files in $input_dir.
421              
422             task "build", sub {
423             # this command will compile all sass files from app/assets/stylesheets
424             # and put the output into public/stylesheets.
425             sass "app/assets/stylesheets",
426             out => "public/stylesheets";
427              
428             # The default is to build all files in assets/sass and put the output
429             # into public/css.
430             sass;
431             };
432              
433             =cut
434              
435             sub sass {
436 0     0 1   my ( $input, %option ) = @_;
437              
438 0 0         unless ($sass_path) {
439 0           $sass_path = "sass";
440             }
441              
442 0 0         unless ($input) {
443 0           $input = "assets/sass";
444             }
445              
446 0 0         if ( !exists $option{out} ) {
447 0           $option{out} = "public/css";
448             }
449              
450 0           Rex::Logger::info("Building sass files...");
451 0           my $ret = run "$sass_path -q --update $input:" . $option{out} . " 2>&1";
452              
453 0 0         if ( $? == 0 ) {
454 0           Rex::Logger::info("...done.");
455             }
456             else {
457 0           Rex::Logger::info("Failed building sass files. $ret");
458 0           die("Failed building sass files.");
459             }
460             }
461              
462             =back
463              
464             =cut
465              
466             1;