package textbender::a::b::demo::Demo; # Copyright 2006-2007, 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 Demonstration build of textbender. =head1 EXPORTS =over 4 =cut BEGIN { use Exporter (); our @ISA; @ISA = qw( Exporter ); our @EXPORT_OK; @EXPORT_OK = qw( build_demo ); } our @EXPORT_OK; =pod =item B (target, described in the accompanying F script) =cut sub build_boot() { use textbender::a::b::Build qw( ensure_dir ); use textbender::a::b::FileSync qw( $from_dir sync_found $to_dir ); print textbender::a::b::Build::call_stack_indentation() . "boot\n"; _compile_boot(); # - - - my $jar_file = ensure_dir(out_dir()) . '/textbender.a.r.page.BootApplet.jar'; textbender::a::b::Java::jar( _compile_boot_class_outdir(), $jar_file ); return $jar_file; } =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() ); my $file; $file = all_in_one_update_jar_a(); -f $file && unlink $file; $file = all_in_one_update_jar_b(); -f $file && unlink $file; } =pod =item B (target, described in the accompanying F script) =cut sub build_demo() { use textbender::a::b::Build qw( %option out_dir ); use textbender::a::b::Console qw( print_score $verbosity ); use textbender::a::b::FileSync qw( sync_to_file ); use textbender::a::b::Java qw( JDK_dir ); use textbender::a::b::base::Base(); our $_build_cache_dir; print textbender::a::b::Build::call_stack_indentation() . "demo\n"; # textbender.jar, and so on # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - { my $to_sign = $option{'sign'}; $option{'sign'} = 0; # temporarilly textbender::a::b::base::Base::build_base(); $option{'sign'} = $to_sign; } # jar.jar, containing all-in-one.jar # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - # Doubles download size, for desk daemon. Needed by # textbender.a.r.desk.HostServiceRegistry.allInOneJar(). print textbender::a::b::Build::call_stack_indentation() . " (jar all-in-one ...\n"; { use File::Copy (); use File::stat qw( stat ); my $command; # copy textbender.jar to all-in-one.jar # ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` my $textbender_jar = out_dir() . '/textbender.jar'; my $all_in_one_jar = $_build_cache_dir . '/textbender-all-in-one.jar'; sync_to_file( $textbender_jar, $all_in_one_jar ); # unjar all other runtime jars # ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` my $runtime_unjar_dir = $_build_cache_dir . '/runtime-unjar'; for my $jar( textbender::a::b::base::Base::runtime_library_jar_list() ) { $command = "unzip -oqu $jar -x META-INF* -d $runtime_unjar_dir"; # jar tool now preserves times (JDK 1.6) but probably still overwrites regardless, when extracting; so using unzip if( $verbosity ) { print "\n$command\n"; print_score( undef, '^' ); } system $command and exit; } # transfer their contents to all-in-one.jar # ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` $command = JDK_dir() . "/bin/jar uf $all_in_one_jar -C $runtime_unjar_dir ."; if( $verbosity ) { print "\n$command\n"; print_score( undef, '^' ); } system $command and exit; # jar all-in-one.jar --> jar.jar # ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` $option{'sign'} && textbender::a::b::JarSigner::sign( $all_in_one_jar ); my $jar_jar = out_dir() . '/jar.jar'; $command = JDK_dir() . "/bin/jar cf0 $jar_jar -C $_build_cache_dir textbender-all-in-one.jar"; if( $verbosity ) { print "\n$command\n"; print_score( undef, '^' ); } system $command and exit; # update in existing runtime, as a testing convenience, # per textbender.a.r.desk.HostServiceRegistry1.allInOneJar() # ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` my $update_jar; update_jar: # oldest of A and B { # Leap frogging the updates, in attempt to prevent browser crash # (apparently from ZIP code of Plug-in 1.6) when reading # the altered all-in-one JAR. (Normally not a problem...) # This does not prevent the crash. Must still restart, every build. # But at least this avoids clobbering the JAR, and allows clean exit. $update_jar = all_in_one_update_jar_a(); -f $update_jar or last; my $update_jar_b = all_in_one_update_jar_b(); -f $update_jar_b && stat($update_jar_b)->mtime > stat($update_jar)->mtime and last; $update_jar = $update_jar_b; } File::Copy::copy( $all_in_one_jar, $update_jar ) or die $!; } # textbender.a.r.page.BootApplet.jar # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - build_boot(); # - - - sync_to_file ( 'textbender/a/b/demo/instructions.xht_source.txt', out_dir() . '/textbender/a/b/demo/instructions.xht' ); unlink out_dir() . '/textbender/a/b/demo/instructions-redirect.xht'; sync_to_file ( 'textbender/a/r/desk/run.jnlp_source.xml', out_dir() . '/textbender.a.r.desk.jnlp' ); $option{'sign'} && textbender::a::b::base::Base::sign_all(); } sub _build_demo_old() { # cf. textbender::a::b::base::Base::build_base() use textbender::a::b::Build qw( %option out_dir ); use textbender::a::b::Console qw( print_score $verbosity ); use textbender::a::b::FileSync qw( $from_dir sync_found sync_to_file $to_dir ); use textbender::a::b::Java qw( compile_class_outdir ); use textbender::a::b::base::Base(); print textbender::a::b::Build::call_stack_indentation() . "demo\n"; build_boot(); # # Deploy runtime library jars too. # # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - # for my $jar( textbender::a::b::base::Base::runtime_library_jar_list() ) # { # my $to_jar = out_dir() . '/' . $jar; # ensure_dir( File::Basename::dirname( $to_jar )); # sync_to_file( $jar, $to_jar ); # } # # Unpack runtime library jars to compile out, # to repack them later (below) into base textbender.jar. # All in one big jar. Because boot launches page daemon # from the JNLP install, by tricking it into revealing its jar files, # and the trick is easier when there's only one jar. # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - for my $jar( textbender::a::b::base::Base::runtime_library_jar_list() ) { my $command = 'unzip -oqu ' . $jar . ' -x META-INF* -d ' . compile_class_outdir(); # jar tool now preserves times (JDK 1.6) but probably still overwrites regardless, when extracting; so using unzip if( $verbosity ) { print "\n$command\n"; print_score( undef, '^' ); } system $command and exit; } # Build the base textbender.jar; # including unpacked content (above) of runtime library jars. # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - textbender::a::b::base::Base::build_jar(); # Deploy demo files, dependencies, and all the rest of the source. # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - $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 sync_found(); }}, $from_dir ); # Deploy the JNLP descriptor. # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - sync_to_file ( 'textbender/a/r/desk/run.jnlp_source.xml', out_dir() . '/textbender.a.r.desk.jnlp' ); # - - - $option{'sign'} && textbender::a::b::base::Base::sign_all(); } ##### I m p l e m e n t a t i o n ######################################################## =pod =back =head1 IMPLEMENTATION =over 4 =cut sub all_in_one_update_jar_a() { return textbender::a::b::Build::target_temp_dir() . '/textbender-all-in-one_update-A.jar'; } sub all_in_one_update_jar_b() { return textbender::a::b::Build::target_temp_dir() . '/textbender-all-in-one_update-B.jar'; } 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/demo' ); } =pod =item B<_compile_boot> Compiles out-of-sync source files *.java to *.class. Returns the number of files compiled. =cut our $_compile_boot__print_count; sub _compile_boot() { # cf. textbender::a::b::Java::_compile() use File::Find (); use textbender::a::b::Console qw( print_score $verbosity ); use textbender::a::b::Build qw( build_cache_root ensure_dir ); use textbender::a::b::Java qw( JDK_dir ); my $compile_class_outdir = ensure_dir( _compile_boot_class_outdir() ); my $command = JDK_dir() . '/bin/javac' . ' -sourcepath .' . " -d $compile_class_outdir" . ' -deprecation -g' # Though deprecation warnings are emitted only for single-file compiles, # with or without -deprecation, in 1.4, # . ' -source ' . textbender::a::b::Java::major_version() ## latest is the default in 1.5 # . ' -target ' . textbender::a::b::Java::major_version() ## latest is the default in 1.5 # . ' -verbose' . ' -Xlint' # new in 1.5 . ' -Xlint:-serial'; # because its documentation (especially for @serialField and @serialData) is incomprehensible local *ARGFILE; my $argfile; # Source. # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - $argfile = build_cache_root() . '/textbender/a/b/Java-compile-arg-source'; open ARGFILE, '>', $argfile or die; { $_compile_boot__print_count = 0; # thus far File::Find::find ( {follow_fast=>1, no_chdir=>1, wanted=>\&_compile_boot__print_all_source}, 'textbender' ); close ARGFILE; } $_compile_boot__print_count or return 0; $command .= ' @' . $argfile; # Classpath. # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - $argfile = build_cache_root() . '/textbender/a/b/Java-compile-arg-classpath'; open ARGFILE, '>', $argfile or die; { print ARGFILE "-classpath $compile_class_outdir"; for my $file ( JDK_dir() . '/jre/lib/plugin.jar' # for JSObject (in-browser code) ){ print ARGFILE ':'; print ARGFILE $file; } # ` ` ` print ARGFILE "\n"; close ARGFILE; } $command .= ' @' . $argfile; # - - - print textbender::a::b::Build::call_stack_indentation() . "(compile $_compile_boot__print_count...\n"; if( $verbosity ) { print "\n$command\n"; print_score( undef, '^' ); } system $command and exit; return $_compile_boot__print_count; } sub _compile_boot__print_all_source() # File::Find::find wanted sub { # cf. textbender::a::b::Java::_compile__print_all_source() my $file = $File::Find::name; -d $file and return; # skip directories my $outfile = $file; # textbender/foo/bar.java $outfile =~ s:\.java$:.class: or return; # textbender/foo/bar.class -l $file && $file =~ m'/\.\#[^/]+$' and die "\nemacs lock file (do you need to save this buffer?): $_\n"; $outfile = _compile_boot_class_outdir() . '/' . $outfile; # /dir/textbender/foo/bar.class if( -f $outfile ) { File::stat::stat($file)->mtime > File::stat::stat($outfile)->mtime or return; } else # finally, filter by path (last because we still want to compile off-path dependencies (pulled in by javac on the last path) that are now out-of-date { $file eq 'textbender/a/r/page/BootApplet.java' or return; } print ARGFILE $file; print ARGFILE "\n"; ++$_compile_boot__print_count; } =pod =item B<_compile_boot_class_outdir> Returns the directory to which compiled Java (*.class) files are output. =cut sub _compile_boot_class_outdir() { use textbender::a::b::Build qw( build_cache_root ); # return build_cache_root() . '/textbender/a/b/demo/compile-out'; return $_build_cache_dir . '/compile-out'; } =pod =back =cut 1;