You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@buildr.apache.org by as...@apache.org on 2008/01/09 08:12:19 UTC

svn commit: r610283 - in /incubator/buildr/trunk: CHANGELOG doc/pages/packaging.textile lib/java/packaging.rb lib/tasks/zip.rb spec/compile_spec.rb spec/java_packaging_spec.rb spec/packaging_helper.rb

Author: assaf
Date: Tue Jan  8 23:12:18 2008
New Revision: 610283

URL: http://svn.apache.org/viewvc?rev=610283&view=rev
Log:
Added: EAR packaging (Victor Hugo Borja)

Modified:
    incubator/buildr/trunk/CHANGELOG
    incubator/buildr/trunk/doc/pages/packaging.textile
    incubator/buildr/trunk/lib/java/packaging.rb
    incubator/buildr/trunk/lib/tasks/zip.rb
    incubator/buildr/trunk/spec/compile_spec.rb
    incubator/buildr/trunk/spec/java_packaging_spec.rb
    incubator/buildr/trunk/spec/packaging_helper.rb

Modified: incubator/buildr/trunk/CHANGELOG
URL: http://svn.apache.org/viewvc/incubator/buildr/trunk/CHANGELOG?rev=610283&r1=610282&r2=610283&view=diff
==============================================================================
--- incubator/buildr/trunk/CHANGELOG (original)
+++ incubator/buildr/trunk/CHANGELOG Tue Jan  8 23:12:18 2008
@@ -3,6 +3,7 @@
 * Added: To run all test cases 'rake spec'.  Test coverage reports will show up in html/coverage.  To run failing tests against, 'rake failing'.
 * Added: Layout class for controlling the project layout.  Also cleaned up places where paths were used instead of path names.
 * Added: HTTP Basic authentication support (Yuen-Chi Lian).
+* Added: EAR packaging (Victor Hugo Borja).
 * Changed: Upgraded to Rake 0.8 and RSpec 1.1.
 * Changed: Resources are now copied to target/resources instead of target/classes, and target/test/resources instead of target/test-resources.
 * Changed: Test cases are not compiled into target/test/classes instead of target/test-classes.

Modified: incubator/buildr/trunk/doc/pages/packaging.textile
URL: http://svn.apache.org/viewvc/incubator/buildr/trunk/doc/pages/packaging.textile?rev=610283&r1=610282&r2=610283&view=diff
==============================================================================
--- incubator/buildr/trunk/doc/pages/packaging.textile (original)
+++ incubator/buildr/trunk/doc/pages/packaging.textile Tue Jan  8 23:12:18 2008
@@ -271,6 +271,84 @@
 }}}
 
 
+h2.  Packaging EARs
+
+EAR packaging is slightly different from JAR/WAR packaging.  It's main purpose
+is to package components together, and so it includes special methods for
+handling component inclusion that take care to update application.xml and the
+component's classpath.
+
+EAR packages support four component types:
+
+* @:war@ -- J2EE Web Application (WAR).
+* @:ejb@ -- Enterprise Java Bean (JAR).
+* @:jar@ -- J2EE Application Client (JAR).
+* @:lib@ -- Shared library (JAR).
+
+This example shows two ways for adding components built by other projects:
+
+{{{!ruby
+package(:ear) << project('coolWebService').package(:war)
+package(:ear).add project('commonLib') # By default, the JAR package
+}}}
+
+Adding a WAR package assumes it's a WAR component and treats it as such, but
+JAR packages can be any of three component types, so by default they are all
+treated as shared libraries.  If you want to add an EJB or Application Client
+component, you need to say so explicitly, either passing @type=>package@, or by
+passing the component type in the @:type@ option.
+
+Here are three examples:
+
+{{{!ruby
+# Assumed to be a shared library.
+package(:ear).add 'org.springframework:spring:jar:2.6'
+# Component type mapped to package.
+package(:ear).add :ejb=>project('beanery')
+# Adding component with specific package type.
+package(:ear).add project('client'), :type=>:jar
+}}}
+
+By default, WAR components are all added under the @/war@ path, and likewise,
+EJB components are added under the @/ejb@ path, shared libraries under @/lib@
+and Application Client components under @/jar@.
+
+If you want to place components in different locations you can do so using the
+@:path@ option, or by specifying a different mapping between component type and
+its path.  The following two examples are equivalent:
+
+{{{!ruby
+# Specify once per component.
+package(:ear).add project('coolWebService').package(:war), :path=>'coolServices'
+# Configure once and apply to all added components.
+package(:ear).map[:war] = 'coolServices'
+package(:ear) << project('coolWebService').package(:war)
+}}}
+
+EAR packages include an @application.xml@ file in the @META-INF@ directory that
+describes the application and its component.  This file is created for you
+during packaging, by referencing all the components added to the EAR.  There
+are a couple of things you will typically want to change.
+
+* *display-name* -- The application's display name defaults to the project's
+identifier.  You can change that by setting the @display_name@ attribute.
+
+* *context-root* -- WAR components specify a context root, based on the package
+identifier, for example, "cool-web-1.0.war" will have the context root
+"cool-web".  To specify a different context root, add the WAR package with the
+@context_root@ option.
+
+Again, by example:
+
+{{{!ruby
+package(:ear).display_name = 'MyCoolWebService'
+package(:ear).add project('coolWebService').package(:war), :context-root=>'coolness'
+}}}
+
+If you need to disable the context root (e.g. for Portlets), set @context_root@
+to @false@.
+
+
 h2.  Packaging Tars and GZipped Tars
 
 Everything you know about working with ZIP files translates to Tar files, the

Modified: incubator/buildr/trunk/lib/java/packaging.rb
URL: http://svn.apache.org/viewvc/incubator/buildr/trunk/lib/java/packaging.rb?rev=610283&r1=610282&r2=610283&view=diff
==============================================================================
--- incubator/buildr/trunk/lib/java/packaging.rb (original)
+++ incubator/buildr/trunk/lib/java/packaging.rb Tue Jan  8 23:12:18 2008
@@ -29,12 +29,13 @@
           initialize_without_manifest *args
           @manifest = false
           @meta_inf = []
+          @dependencies = FileList[]
 
           prepare do
             @prerequisites << manifest if String === manifest || Rake::Task === manifest
             [meta_inf].flatten.map { |file| file.to_s }.uniq.each { |file| path('META-INF').include file }
           end
-
+        
           enhance do
             if manifest
               # Tempfiles gets deleted on garbage collection, so we're going to hold on to it
@@ -125,6 +126,7 @@
 
       end
 
+
       # Extends the JarTask to create a WAR file.
       #
       # Supports all the same options as JarTask, in additon to these two options:
@@ -163,6 +165,7 @@
   
       end
 
+
       # Extends the JarTask to create an AAR file (Axis2 service archive).
       #
       # Supports all the same options as JarTask, with the addition of :wsdls, :services_xml and :libs.
@@ -209,6 +212,205 @@
       end
 
 
+      # Extend the JarTask to create an EAR file.
+      #
+      # The following component types are supported by the EARTask:
+      #
+      # * :war -- A J2EE Web Application
+      # * :ejb -- An Enterprise Java Bean
+      # * :jar -- A J2EE Application Client.[1]
+      # * :lib -- An ear scoped shared library[2] (for things like logging,
+      #           spring, etc) common to the ear components
+      #
+      # The EarTask uses the "Mechanism 2: Bundled Optional Classes" as described on [2].
+      # All specified libraries are added to the EAR archive and the Class-Path manifiest entry is
+      # modified for each EAR component. Special care is taken with WebApplications, as they can
+      # contain libraries on their WEB-INF/lib directory, libraries already included in a war file
+      # are not referenced by the Class-Path entry of the war in order to avoid class collisions
+      #
+      # EarTask supports all the same options as JarTask, in additon to these two options:
+      #
+      # * :display_name -- The displayname to for this ear on application.xml
+      #
+      # * :map -- A Hash used to map component type to paths within the EAR.
+      #     By default each component type is mapped to a directory with the same name,
+      #     for example, EJBs are stored in the /ejb path.  To customize:
+      #                       package(:ear).dirs[:war] = 'web-applications' 
+      #                       package(:ear).dirs[:lib] = nil # store shared libraries on root of archive
+      #
+      # EAR components are added by means of the EarTask#add, EarTask#<<, EarTask#push methods
+      # Component type is determined from the artifact's type. 
+      #
+      #      package(:ear) << project('coolWebService').package(:war)
+      #
+      # The << method is just an alias for push, with the later you can add multiple components
+      # at the same time. For example.. 
+      #
+      #      package(:ear).push 'org.springframework:spring:jar:2.6', 
+      #                                   projects('reflectUtils', 'springUtils'),
+      #                                   project('coolerWebService').package(:war)
+      #
+      # The add method takes a single component with an optional hash. You can use it to override
+      # some component attributes.
+      #
+      # You can override the component type for a particular artifact. The following example
+      # shows how you can tell the EarTask to treat a JAR file as an EJB:
+      #
+      #      # will add an ejb entry for the-cool-ejb-2.5.jar in application.xml
+      #      package(:ear).add 'org.coolguys:the-cool-ejb:jar:2.5', :type=>:ejb
+      #      # A better syntax for this is: 
+      #      package(:ear).add :ejb=>'org.coolguys:the-cool-ejb:jar:2.5'
+      #
+      # By default, every JAR package is assumed to be a library component, so you need to specify
+      # the type when including an EJB (:ejb) or Application Client JAR (:jar).
+      #
+      # For WebApplications (:war)s, you can customize the context-root that appears in application.xml.
+      # The following example also specifies a different directory inside the EAR where to store the webapp.
+      #
+      #      package(:ear).add project(:remoteService).package(:war), 
+      #                                 :path => 'web-services', :context_root => '/Some/URL/Path'
+      #
+      # [1] http://java.sun.com/j2ee/sdk_1.2.1/techdocs/guides/ejb/html/Overview5.html#10106
+      # [2] http://java.sun.com/j2ee/verified/packaging.html
+      class EarTask < JarTask
+        
+        SUPPORTED_TYPES = [:war, :ejb, :jar, :rar, :lib]
+
+        # The display-name entry for application.xml
+        attr_accessor :display_name
+        # Map from component type to path inside the EAR.
+        attr_accessor :map
+
+        def initialize(*args)
+          super
+          @map = Hash.new { |h, k| k.to_s }
+          @libs, @components = [], []
+          prepare do
+            @components.each do |component|
+              path(component[:path]).include(component[:artifact])
+            end
+            path('META-INF').include(descriptor)
+          end
+        end
+
+        # Add an artifact to this EAR.
+        def add(*args)
+          options = Hash === args.last ? args.pop.clone : {}
+          if artifact = args.shift
+            type = options[:type]
+            unless type
+              type = artifact.respond_to?(:type) ? artifact.type : artifact.pathmap('%x').to_sym
+              type = :lib if type == :jar
+              raise "Unknown EAR component type: #{type}. Perhaps you may explicity tell what component type to use." unless
+                SUPPORTED_TYPES.include?(type)
+            end
+          else
+            type = SUPPORTED_TYPES.find { |type| options[type] }
+            artifact = Buildr.artifact(options[type])
+          end
+
+          component = options.merge(:artifact=>artifact, :type=>type,
+            :id=>artifact.respond_to?(:to_spec) ? artifact.id : artifact.to_s.pathmap('%n'),
+            :path=>options[:path] || map[type].to_s)
+          file(artifact.to_s).enhance do |task|
+            task.enhance { |task| update_classpath(task.name) }
+          end unless :lib == type
+          @components << component
+          self
+        end
+
+        def push(*artifacts)
+          artifacts.flatten.each { |artifact| add artifact }
+          self
+        end
+        alias_method :<<, :push
+
+      protected
+
+        def associate(project)
+          @project = project
+        end
+
+        def path_to(*args) #:nodoc:
+          @project.path_to(:target, :ear, *args)
+        end
+        alias_method :_, :path_to
+
+        def update_classpath(package)
+          Zip::ZipFile.open(package) do |zip|
+            # obtain the manifest file
+            manifest = zip.read('META-INF/MANIFEST.MF').split("\n\n")
+            manifest.first.gsub!(/([^\n]{71})\n /,"\\1")
+            manifest.first << "Class-Path: \n" unless manifest.first =~ /Class-Path:/
+            # Determine which libraries are already included.
+            included_libs = manifest.first[/^Class-Path:\s+(.*)$/, 1].split(/\s+/).map { |fn| File.basename(fn) }
+            included_libs += zip.entries.map(&:to_s).select { |fn| fn =~ /^WEB-INF\/lib\/.+/ }.map { |fn| File.basename(fn) }
+            # Include all other libraries in the classpath.
+            libs_classpath.reject { |path| included_libs.include?(File.basename(path)) }.each do |path|
+              manifest.first.sub!(/^Class-Path:/, "\\0 #{path}\n ")
+            end
+
+            Tempfile.open 'MANIFEST.MF' do |temp|
+              temp.write manifest.join("\n\n")
+              temp.flush
+              # Update the manifest.
+              if Buildr::Java.jruby?
+                Buildr.ant("update-jar") do |ant|
+                  ant.jar :destfile => task.name, :manifest => temp.path, 
+                          :update => 'yes', :whenmanifestonly => 'create'
+                end
+              else
+                zip.replace('META-INF/MANIFEST.MF', temp.path)
+              end
+            end
+          end
+        end
+  
+      private
+
+        # Classpath of all packages included as libraries (type :lib).
+        def libs_classpath
+          @classpath = @components.select { |comp| comp[:type] == :lib }.
+            map { |comp| File.expand_path(File.join(comp[:path], File.basename(comp[:artifact].to_s)), '/')[1..-1] }
+        end
+
+        # return a FileTask to build the ear application.xml file
+        def descriptor
+          @descriptor ||= file('META-INF/application.xml') do |task|
+            mkpath File.dirname(task.name), :verbose=>false
+            File.open task.name, 'w' do |file|
+              xml = Builder::XmlMarkup.new(:target=>file, :indent => 2)
+              xml.declare! :DOCTYPE, :application, :PUBLIC, 
+                           "-//Sun Microsystems, Inc.//DTD J2EE Application 1.2//EN",
+                           "http://java.sun.com/j2ee/dtds/application_1_2.dtd"
+              xml.application do
+                xml.tag! 'display-name', display_name
+                @components.each do |comp|
+                  uri = File.expand_path(File.join(comp[:path], File.basename(comp[:artifact].to_s)), '/')[1..-1]
+                  case comp[:type]
+                  when :war
+                    xml.module :id=>comp[:id] do
+                      xml.web do 
+                        xml.tag! 'web-uri', uri
+                        xml.tag! 'context-root', File.join('', (comp[:context_root] || comp[:id])) unless comp[:context_root] == false
+                      end
+                    end
+                  when :ejb
+                    xml.module :id=>comp[:id] do
+                      xml.ejb uri
+                    end
+                  when :jar
+                    xml.jar uri
+                  end
+                end
+              end
+            end
+          end
+        end
+
+      end
+
+
       include Extension
 
       before_define do |project|
@@ -319,6 +521,13 @@
           aar.with compile.target unless compile.sources.empty?
           aar.with resources.target unless resources.sources.empty?
           aar.with :libs=>compile.dependencies
+        end
+      end
+
+      def package_as_ear(file_name) #:nodoc:
+        Java::Packaging::EarTask.define_task(file_name).tap do |ear|
+          ear.send :associate, self
+          ear.with :display_name=>id, :manifest=>manifest, :meta_inf=>meta_inf
         end
       end
 

Modified: incubator/buildr/trunk/lib/tasks/zip.rb
URL: http://svn.apache.org/viewvc/incubator/buildr/trunk/lib/tasks/zip.rb?rev=610283&r1=610282&r2=610283&view=diff
==============================================================================
--- incubator/buildr/trunk/lib/tasks/zip.rb (original)
+++ incubator/buildr/trunk/lib/tasks/zip.rb Tue Jan  8 23:12:18 2008
@@ -73,6 +73,7 @@
         self
       end
       alias :add :include
+      alias :<< :include
 
       # :call-seq:
       #   exclude(*files) => self
@@ -175,6 +176,7 @@
         @includes |= files
         self
       end
+      alias :<< :include
 
       def exclude(*files)
         @excludes |= files
@@ -264,6 +266,7 @@
       self
     end 
     alias :add :include
+    alias :<< :include
    
     # :call-seq:
     #   exclude(*files) => self

Modified: incubator/buildr/trunk/spec/compile_spec.rb
URL: http://svn.apache.org/viewvc/incubator/buildr/trunk/spec/compile_spec.rb?rev=610283&r1=610282&r2=610283&view=diff
==============================================================================
--- incubator/buildr/trunk/spec/compile_spec.rb (original)
+++ incubator/buildr/trunk/spec/compile_spec.rb Tue Jan  8 23:12:18 2008
@@ -353,6 +353,13 @@
     suppress_stdout { compile_task.from('failed.java').invoke rescue nil }
     File.stat(compile_task.target.to_s).mtime.should be_close(Time.now - 10, 2)
   end
+
+  it 'should complain if source directories and no compiler selected' do
+    mkpath 'sources'
+    define 'bar' do
+      lambda { compile.from('sources').invoke }.should raise_error(RuntimeError, /no compiler selected/i)
+    end
+  end
 end
 
 

Modified: incubator/buildr/trunk/spec/java_packaging_spec.rb
URL: http://svn.apache.org/viewvc/incubator/buildr/trunk/spec/java_packaging_spec.rb?rev=610283&r1=610282&r2=610283&view=diff
==============================================================================
--- incubator/buildr/trunk/spec/java_packaging_spec.rb (original)
+++ incubator/buildr/trunk/spec/java_packaging_spec.rb Tue Jan  8 23:12:18 2008
@@ -245,7 +245,7 @@
   def inspect_meta_inf
     package = project('foo').package(@packaging)
     package.invoke
-    assumed = Array(@meta_inf)
+    assumed = Array(@meta_inf_ignore)
     Zip::ZipFile.open(package.to_s) do |zip|
       entries = zip.entries.map(&:to_s).select { |f| File.dirname(f) == 'META-INF' }.map { |f| File.basename(f) }
       assumed.each { |f| entries.should include(f) }
@@ -314,7 +314,7 @@
   before { @packaging = :jar }
   it_should_behave_like 'package with manifest'
   it_should_behave_like 'package with meta_inf'
-  before { @meta_inf = ['MANIFEST.MF'] }
+  before { @meta_inf_ignore = 'MANIFEST.MF' }
 
   it 'should use files from compile directory if nothing included' do
     write 'src/main/java/Test.java', 'class Test {}'
@@ -368,7 +368,7 @@
   before { @packaging = :war }
   it_should_behave_like 'package with manifest'
   it_should_behave_like 'package with meta_inf'
-  before { @meta_inf = ['MANIFEST.MF'] }
+  before { @meta_inf_ignore = 'MANIFEST.MF' }
 
   def make_jars
     artifact('group:id:jar:1.0') { |t| write t.to_s }
@@ -465,9 +465,10 @@
   before { @packaging = :aar }
   it_should_behave_like 'package with manifest'
   it_should_behave_like 'package with meta_inf'
-  before { @meta_inf = ['MANIFEST.MF', 'services.xml'] }
-
-  setup { write 'src/main/axis2/services.xml' }
+  before do
+    write 'src/main/axis2/services.xml'
+    @meta_inf_ignore = ['MANIFEST.MF', 'services.xml']
+  end
 
   def make_jars
     artifact('group:id:jar:1.0') { |t| write t.to_s }
@@ -538,6 +539,291 @@
     project('foo').package(:aar).libs.should include(artifact('additional:id:jar:1.0'))
   end
 
+end
+
+
+describe Packaging, 'ear' do
+  it_should_behave_like 'packaging'
+  before { @packaging = :ear }
+  it_should_behave_like 'package with manifest'
+  it_should_behave_like 'package with meta_inf'
+  before { @meta_inf_ignore = ['MANIFEST.MF', 'application.xml'] }
+
+  def inspect_ear
+    project('foo').package(:ear).invoke
+    Zip::ZipFile.open(project('foo').package(:ear).to_s) do |ear|
+      yield ear.entries.map(&:to_s).sort
+    end
+  end
+
+  def inspect_application_xml
+    project('foo').package(:ear).invoke
+    Zip::ZipFile.open(project('foo').package(:ear).to_s) do |ear|
+      yield REXML::Document.new(ear.read('META-INF/application.xml')).root
+    end
+  end
+
+  def inspect_classpath(package)
+    project('foo').package(:ear).invoke
+    Zip::ZipFile.open(project('foo').package(:ear).to_s) do |ear|
+      File.open('tmp.zip', 'w') do |tmp|
+        tmp.write ear.file.read(package)
+      end
+      Zip::ZipFile.open('tmp.zip') do |zip|
+        first_section = zip.file.read('META-INF/MANIFEST.MF').split("\n\n").first.
+          split("\n").each { |line| line.length.should < 72 }.
+          inject([]) { |merged, line|
+            if line[0] == 32
+              merged.last << line[1..-1]
+            else
+              merged << line
+            end
+            merged
+          }.map { |line| line.split(/: /) }.
+          inject({}) { |map, (name, value)| map.merge(name=>value) }
+        yield first_section['Class-Path'].to_s.split(' ')
+      end
+    end
+  end
+
+  it 'should set display name from project id' do
+    define 'foo', :version=>'1.0' do
+      package(:ear).display_name.should eql('foo')
+      define 'bar' do
+        package(:ear).display_name.should eql('foo-bar')
+      end
+    end
+  end
+
+  it 'should set display name in application.xml' do
+    define 'foo', :version=>'1.0' do
+      package(:ear)
+    end
+    inspect_application_xml { |xml| xml.get_text('/application/display-name').should == 'foo' }
+  end
+
+  it 'should accept different display name' do
+    define 'foo', :version=>'1.0' do
+      package(:ear).display_name = 'bar'
+    end
+    inspect_application_xml { |xml| xml.get_text('/application/display-name').should == 'bar' }
+  end
+
+  it 'should map WARs to /war directory' do
+    define 'foo', :version=>'1.0' do
+      package(:ear) << package(:war)
+    end
+    inspect_ear { |files| files.should include('war/foo-1.0.war') }
+  end
+
+  it 'should map EJBs to /ejb directory' do
+    define 'foo', :version=>'1.0' do
+      package(:ear).add :ejb=>package(:jar)
+    end
+    inspect_ear { |files| files.should include('ejb/foo-1.0.jar') }
+  end
+
+  it 'should map JARs to /lib directory' do
+    define 'foo', :version=>'1.0' do
+      package(:ear) << package(:jar)
+    end
+    inspect_ear { |files| files.should include('lib/foo-1.0.jar') }
+  end
+
+  it 'should accept component type with :type option' do
+    define 'foo', :version=>'1.0' do
+      package(:ear).add package(:jar), :type=>:ejb
+    end
+    inspect_ear { |files| files.should include('ejb/foo-1.0.jar') }
+  end
+
+  it 'should accept component and its type as type=>artiract' do
+    define 'foo', :version=>'1.0' do
+      package(:ear).add :ejb=>package(:jar)
+    end
+    inspect_ear { |files| files.should include('ejb/foo-1.0.jar') }
+  end
+
+  it 'should map typed JARs to /jar directory' do
+    define 'foo', :version=>'1.0' do
+      package(:ear).add :jar=>package(:jar)
+    end
+    inspect_ear { |files| files.should include('jar/foo-1.0.jar') }
+  end
+
+  it 'should complain about unknown component type' do
+    define 'foo', :version=>'1.0' do
+      lambda { package(:ear).add package(:zip) }.should raise_error(RuntimeError, /unknown ear component type/i)
+    end
+  end
+
+  it 'should allow unknown component types with explicit type' do
+    define 'foo', :version=>'1.0' do
+      package(:ear).add :lib=>package(:zip)
+    end
+    inspect_ear { |files| files.should include('lib/foo-1.0.zip') }
+  end
+
+  it 'should accept alternative directory name' do
+    define 'foo', :version=>'1.0' do
+      package(:ear).add package(:jar), :path=>'trash'
+    end
+    inspect_ear { |files| files.should include('trash/foo-1.0.jar') }
+  end
+
+  it 'should accept customization of directory map' do
+    define 'foo', :version=>'1.0' do
+      package(:ear).map[:jar] = 'jarred'
+      package(:ear).add :jar=>package(:jar)
+    end
+    inspect_ear { |files| files.should include('jarred/foo-1.0.jar') }
+  end
+
+  it 'should accept customization of directory map with nil paths in application.xml' do
+    define 'foo', :version=>'1.0' do
+      package(:ear).map[:war] = nil
+      package(:ear).add :war=>package(:war)
+      package(:ear).add package(:jar)
+    end
+    inspect_ear { |files| files.should include('foo-1.0.war') }
+    inspect_application_xml do |xml|
+      xml.get_text("/application/module[@id='foo']/web/web-uri").to_s.should eql('foo-1.0.war')
+    end
+  end
+
+  it 'should accept customization of directory map with nil paths in the classpath' do
+    define 'foo', :version=>'1.0' do
+      package(:ear).map[:lib] = nil
+      package(:ear).add :war=>package(:war)
+      package(:ear) << package(:jar)
+    end
+    inspect_classpath 'war/foo-1.0.war' do |classpath|
+      classpath.should include('foo-1.0.jar')
+    end
+  end
+
+  it 'should list WAR components in application.xml' do
+    define 'foo', :version=>'1.0' do
+      package(:ear) << package(:war) << package(:war, :id=>'bar')
+    end
+    inspect_application_xml do |xml|
+      xml.get_elements("/application/module[@id='foo'][web]").should_not be_empty
+      xml.get_elements("/application/module[@id='bar'][web]").should_not be_empty
+    end
+  end
+
+  it 'should specify web-uri for WAR components in application.xml' do
+    define 'foo', :version=>'1.0' do
+      package(:ear) << package(:war)
+      package(:ear).add package(:war, :id=>'bar'), :path=>'ws'
+    end
+    inspect_application_xml do |xml|
+      xml.get_text("/application/module[@id='foo']/web/web-uri").to_s.should eql('war/foo-1.0.war')
+      xml.get_text("/application/module[@id='bar']/web/web-uri").to_s.should eql('ws/bar-1.0.war')
+    end
+  end
+
+  it 'should specify context-root for WAR components in application.xml' do
+    define 'foo', :version=>'1.0' do
+      package(:ear) << package(:war)
+      package(:ear).add package(:war, :id=>'bar')
+    end
+    inspect_application_xml do |xml|
+      xml.get_text("/application/module[@id='foo']/web/context-root").to_s.should eql('/foo')
+      xml.get_text("/application/module[@id='bar']/web/context-root").to_s.should eql('/bar')
+    end
+  end
+
+  it 'should accept context-root for WAR components in application.xml' do
+    define 'foo', :version=>'1.0' do
+      package(:ear).add package(:war), :context_root=>'rooted'
+    end
+    inspect_application_xml do |xml|
+      xml.get_text("/application/module[@id='foo']/web/context-root").to_s.should eql('/rooted')
+    end
+  end
+
+  it 'should allow disabling the context root' do
+    define 'foo', :version=>'1.0' do
+      package(:ear).add package(:war), :context_root=>false
+    end
+    inspect_application_xml do |xml|
+      xml.get_elements("/application/module[@id='foo']/web/context-root").should be_empty
+    end
+  end
+
+  it 'should list EJB components in application.xml' do
+    define 'foo', :version=>'1.0' do
+      package(:ear).add :ejb=>package(:jar)
+      package(:ear).add :ejb=>package(:jar, :id=>'bar')
+    end
+    inspect_application_xml do |xml|
+      xml.get_text("/application/module[@id='foo']/ejb").to_s.should eql('ejb/foo-1.0.jar')
+      xml.get_text("/application/module[@id='bar']/ejb").to_s.should eql('ejb/bar-1.0.jar')
+    end
+  end
+
+  it 'should list JAR components in application.xml' do
+    define 'foo', :version=>'1.0' do
+      package(:ear) << { :jar=>package(:jar) } << { :jar=>package(:jar, :id=>'bar') }
+    end
+    inspect_application_xml do |xml|
+      jars = xml.get_elements('/application/jar').map(&:texts).map(&:to_s)
+      jars.should include('jar/foo-1.0.jar', 'jar/bar-1.0.jar')
+    end
+  end
+
+  it 'should update WAR component classpath to include libraries' do
+    define 'foo', :version=>'1.0' do
+      package(:ear) << package(:jar, :id=>'lib1') << package(:jar, :id=>'lib2')
+      package(:ear).add package(:war)
+    end
+    inspect_classpath 'war/foo-1.0.war' do |classpath|
+      classpath.should include('lib/lib1-1.0.jar', 'lib/lib2-1.0.jar')
+    end
+  end
+
+  it 'should update WAR component classpath but skip internal libraries' do
+    define 'foo', :version=>'1.0' do
+      package(:ear) << package(:jar, :id=>'lib1') << package(:jar, :id=>'lib2')
+      package(:war).with(:libs=>package(:jar, :id=>'lib1'))
+      package(:ear).add package(:war)
+    end
+    inspect_classpath 'war/foo-1.0.war' do |classpath|
+      classpath.should_not include('lib/lib1-1.0.jar')
+      classpath.should include('lib/lib2-1.0.jar')
+    end
+  end
+
+  it 'should update EJB component classpath to include libraries' do
+    define 'foo', :version=>'1.0' do
+      package(:ear) << package(:jar, :id=>'lib1') << package(:jar, :id=>'lib2')
+      package(:ear).add :ejb=>package(:jar)
+    end
+    inspect_classpath 'ejb/foo-1.0.jar' do |classpath|
+      classpath.should include('lib/lib1-1.0.jar', 'lib/lib2-1.0.jar')
+    end
+  end
+
+  it 'should update JAR component classpath to include libraries' do
+    define 'foo', :version=>'1.0' do
+      package(:ear) << package(:jar, :id=>'lib1') << package(:jar, :id=>'lib2')
+      package(:ear).add :jar=>package(:jar)
+    end
+    inspect_classpath 'jar/foo-1.0.jar' do |classpath|
+      classpath.should include('lib/lib1-1.0.jar', 'lib/lib2-1.0.jar')
+    end
+  end
+
+  it 'should deal with very long classpaths' do
+    define 'foo', :version=>'1.0' do
+      20.times { |i| package(:ear) << package(:jar, :id=>"lib#{i}") }
+      package(:ear).add :jar=>package(:jar)
+    end
+    inspect_classpath 'jar/foo-1.0.jar' do |classpath|
+      classpath.should include('lib/lib1-1.0.jar', 'lib/lib2-1.0.jar')
+    end
+  end
 end
 
 

Modified: incubator/buildr/trunk/spec/packaging_helper.rb
URL: http://svn.apache.org/viewvc/incubator/buildr/trunk/spec/packaging_helper.rb?rev=610283&r1=610282&r2=610283&view=diff
==============================================================================
--- incubator/buildr/trunk/spec/packaging_helper.rb (original)
+++ incubator/buildr/trunk/spec/packaging_helper.rb Tue Jan  8 23:12:18 2008
@@ -45,5 +45,3 @@
     end
   end
 end
-
-