package textbender::a::b::base::Base; # Copyright 2006, Michael Allan. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Textbender Software"), to deal in the Textbender Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicence, and/or sell copies of the Textbender Software, and to permit persons to whom the Textbender Software is furnished to do so, subject to the following conditions: The preceding copyright notice and this permission notice shall be included in all copies or substantial portions of the Textbender Software. THE TEXTBENDER SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE TEXTBENDER SOFTWARE OR THE USE OR OTHER DEALINGS IN THE TEXTBENDER SOFTWARE. use strict; use warnings; =pod =head1 DESCRIPTION Basic build of textbender. =head1 EXPORTS =over 4 =cut BEGIN { use Exporter (); our @ISA; @ISA = qw( Exporter ); our @EXPORT_OK; @EXPORT_OK = qw( build_base ); } our @EXPORT_OK; =pod =item B (target, described in the accompanying F script) =cut sub build_base() { use textbender::a::b::Build qw( ensure_dir %option ); use textbender::a::b::FileSync qw( $from_dir sync_found sync_to_file $to_dir ); use textbender::a::b::Java qw( javadoc ); print textbender::a::b::Build::call_stack_indentation() . "base\n"; # textbender.jar # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - build_jar(); # runtime library jars too # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - for my $jar( runtime_library_jar_list() ) { my $to_jar = out_dir() . '/' . $jar; ensure_dir( File::Basename::dirname( $to_jar )); sync_to_file( $jar, $to_jar ); } # loose source, so the user has documentation, scripts, and so on # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - $from_dir = 'textbender'; $to_dir = out_dir() . '/textbender'; File::Find::find( {follow_fast=>1, no_chdir=>1, wanted=>sub { m'\.jar$' and return; # the jars we need were deployed above $_ eq 'package.html' and return; # else subsequent build_javadoc will complain: "Multiple sources of package comments found for package" sync_found(); }}, $from_dir ); # - - - _create_executable_jar( 'textbender.a.r.desk' ); _create_executable_jar( 'textbender.a.u.branch' ); _create_executable_jar( 'textbender.a.u.encoding' ); $option{'sign'} && sign_all(); } =pod =item B (target, described in the accompanying F script) =cut sub build_clean() { use File::Path qw( rmtree ); use textbender::a::b::Build qw( build_cache_root out_dir ); print textbender::a::b::Build::call_stack_indentation() . "clean\n"; rmtree( build_cache_root() . "/textbender" ); rmtree( out_dir() ); } =pod =item B (target, described in the accompanying F script) =cut sub build_jar() { use textbender::a::b::Build qw( ensure_dir ); use textbender::a::b::Java qw( compile compile_class_outdir ); print textbender::a::b::Build::call_stack_indentation() . "jar\n"; compile(); # Jar the source too, for runtime access. # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - $from_dir = '.'; $to_dir = compile_class_outdir(); File::Find::find( {follow_fast=>1, no_chdir=>1, wanted=>sub { m'\.jar$' and return; # no need of jars in jar sync_found(); }}, $from_dir ); # - - - my $jar_file = ensure_dir(out_dir()) . '/textbender.jar'; textbender::a::b::Java::jar( compile_class_outdir(), $jar_file ); return $jar_file; } =pod =item B (target, described in the accompanying F script) =cut sub build_javadoc() { use textbender::a::b::Java qw( compile javadoc ); print textbender::a::b::Build::call_stack_indentation() . "javadoc\n"; compile(); javadoc(); } =pod =item B Returns the list of all library jars needed at runtime. The list is cached. =cut sub runtime_library_jar_list() { use textbender::a::b::Java qw( list_found_jar @list_found_jar ); our @_runtime_library_jar; # cached if( !@_runtime_library_jar ) # then lazilly create it { @list_found_jar = (); File::Find::find( {follow_fast=>1, no_chdir=>1, wanted=>sub { my $f = $File::Find::name; # # $f eq 'textbender/a/b/base/editor/jaxe/Jaxe.jar' and return; # not needed, q.v. # # $f eq 'textbender/o/servlet-api.jar' and return; # not needed $f eq 'textbender/o/junit.jar' and return; # not needed list_found_jar(); }}, 'textbender' ); @_runtime_library_jar = @list_found_jar; } return @_runtime_library_jar; } =pod =item B( [$I] ) Signs all jars in the output directory. Defaults to the output directory. =cut sub sign_all( ;$ ) { use textbender::a::b::Build qw( out_dir ); use textbender::a::b::JarSigner (); use textbender::a::b::Java qw( list_found_jar @list_found_jar ); my $dir = shift; $dir or $dir = out_dir(); our $_build_cache_dir; my $target_file = $_build_cache_dir . '/sign-target'; my @jar_to_sign; @list_found_jar = (); File::Find::find( {follow_fast=>1, no_chdir=>1, wanted=>\&list_found_jar}, $dir ); for my $jar( @list_found_jar ) { if( -f $target_file ) { File::stat::stat($jar)->mtime > File::stat::stat($target_file)->mtime or next; } push( @jar_to_sign, $jar ); } @jar_to_sign or return; print textbender::a::b::Build::call_stack_indentation() . '(sign jars ' . scalar @jar_to_sign . "...\n"; for my $jar( @jar_to_sign ) { textbender::a::b::JarSigner::sign( $jar ); } system( "touch $target_file" ); } =pod =back =cut ##### I m p l e m e n t a t i o n ######################################################## =pod =back =head1 IMPLEMENTATION =over 4 =cut our $_build_cache_dir; { use textbender::a::b::Build qw( build_cache_root ensure_dir ); $_build_cache_dir = ensure_dir( build_cache_root() . '/textbender/a/b/base' ); } =pod =item B<_create_executable_jar>( $package_name ) Creates $package_name.jar as executable for class $package_name.Run. =cut sub _create_executable_jar( $ ) { use textbender::a::b::Console qw( print_score $verbosity ); use textbender::a::b::Java qw( JDK_dir list_found_jar @list_found_jar ); my $package_name = shift; my $manifest_file = $_build_cache_dir . '/executable-jar-manifest'; open FILE, '>', $manifest_file or die; { print FILE "Main-Class: $package_name.Run\n"; print FILE 'Class-Path: textbender.jar'; for my $jar( runtime_library_jar_list() ) { print FILE ' ' . $jar; } print FILE "\n"; close FILE; # ^ beware above: "the last line of a manifest file will not be parsed if it doesn't end with a new line character." } my $exec_jar_file = out_dir() . "/$package_name.jar"; my $command = JDK_dir() . "/bin/jar cmf $manifest_file $exec_jar_file"; # empty, but for manifest if( $verbosity ) { print "\n$command\n"; print_score( undef, '^' ); } system( $command ) and exit; } 1;