Author: assaf
Date: Tue Apr 8 13:31:32 2008
New Revision: 646061
URL: http://svn.apache.org/viewvc?rev=646061&view=rev
Log:
I think it's about time we have a class to handle Manifests.
Modified:
incubator/buildr/trunk/lib/buildr/java/packaging.rb
incubator/buildr/trunk/spec/java_packaging_spec.rb
Modified: incubator/buildr/trunk/lib/buildr/java/packaging.rb
URL:
http://svn.apache.org/viewvc/incubator/buildr/trunk/lib/buildr/java/packaging.rb?rev=646061&r1=646060&r2=646061&view=diff
==============================================================================
--- incubator/buildr/trunk/lib/buildr/java/packaging.rb (original)
+++ incubator/buildr/trunk/lib/buildr/java/packaging.rb Tue Apr 8 13:31:32 2008
@@ -23,81 +23,103 @@
# Adds packaging for Java projects: JAR, WAR, AAR, EAR, Javadoc.
module Java
- # Adds support for MANIFEST.MF and other META-INF files.
- module WithManifest #:nodoc:
+ class Manifest
- MANIFEST_HEADER = ['Manifest-Version: 1.0', 'Created-By: Buildr']
- MANIFEST_LINE_SEP = /\r\n|\n|\r[^\n]/
- MANIFEST_SECTION_SEP = /(#{MANIFEST_LINE_SEP}){2}/
+ STANDARD_HEADER = "Manifest-Version: 1.0\nCreated-By: Buildr\n"
+ LINE_SEPARATOR = /\r\n|\n|\r[^\n]/ #:nodoc:
+ SECTION_SEPARATOR = /(#{LINE_SEPARATOR}){2}/ #:nodoc:
class << self
- def included(base)
- base.class_eval do
- alias :initialize_without_manifest :initialize
- alias :initialize :initialize_with_manifest
- end
+
+ def parse(str)
+ sections = str.split(SECTION_SEPARATOR).reject { |s|
s.strip.empty? }
+ new sections.map { |section|
+ lines = section.split(LINE_SEPARATOR).inject([]) { |merged, line|
+ if line[0] == 32
+ merged.last << line[1..-1]
+ else
+ merged << line
+ end
+ merged
+ }
+ lines.map { |line| line.scan(/(.*?):\s*(.*)/).first }.
+ inject({}) { |map, (key, value)| map.merge(key=>value) }
+ }
end
- # from_file(path) => Array of hashes (sections of manifest)
- #
- # The array returned by this function can be feed to
- # WithManifest#manifest_lines_from
- # to obtain the formatted manifest content.
- def from_file(file)
+ def from_zip(file)
Zip::ZipFile.open(file.to_s) do |zip|
- return [{}] unless zip.get_entry('META-INF/MANIFEST.MF')
- zip.read('META-INF/MANIFEST.MF').split(MANIFEST_SECTION_SEP).
- reject { |s| s.chomp == "" }.map do |section|
- section.split(MANIFEST_LINE_SEP).inject([]) { |merged, line|
- if line[0] == 32
- merged.last << line[1..-1]
- else
- merged << line
- end
- merged
- }.map { |line| line.split(/:\s+/) }.
- inject({}) { |map, (name, value)| map.merge(name => value) }
- end
- end
- end
-
- def manifest_lines_from(arg)
- case arg
- when Hash
- arg.map { |name, value| "#{name}: #{value}" }.sort.
- map { |line| manifest_wrap_at_72(line) }.flatten
- when Array
- arg.map { |section|
- name = section.has_key?('Name') ? ["Name: #{section['Name']}"]
: []
- name + section.except('Name').map { |name, value| "#{name}:
#{value}" }.sort + ['']
- }.flatten.map { |line| manifest_wrap_at_72(line) }.flatten
- when Proc, Method
- manifest_lines_from(arg.call)
- when String
- arg.split("\n").map { |line| manifest_wrap_at_72(line) }.flatten
- else
- fail 'Invalid manifest, expecting Hash, Array, file name/task or
proc/method.'
+ return Manifest.new unless zip.get_entry('META-INF/MANIFEST.MF')
+ Manifest.parse zip.read('META-INF/MANIFEST.MF')
end
end
- # update_manifest(file) { |manifest_sections| ... }
+ # update_manifest(file) { |manifest| ... }
def update_manifest(file)
- sections = from_file(file.to_s)
- result = yield sections
+ manifest = from_zip(file)
+ result = yield manifest
Zip::ZipFile.open(file.to_s) do |zip|
zip.get_output_stream('META-INF/MANIFEST.MF') do |out|
- out.write WithManifest.manifest_lines_from(sections).join("\n")
+ out.write manifest.to_s
out.write "\n"
end
end
result
end
- private
- def manifest_wrap_at_72(arg)
- #return arg.map { |line| manifest_wrap_at_72(line)
}.flatten.join("\n") if Array === arg
- return arg if arg.size < 72
- [ arg[0..70], manifest_wrap_at_72(' ' + arg[71..-1]) ]
+ end
+
+ def initialize(arg = nil)
+ case arg
+ when nil, Hash then @sections = [arg || {}]
+ when Array then @sections = arg
+ when String then @sections = Manifest.parse(arg).sections
+ when Proc, Method then @sections = Manifest.parse(arg.call).sections
+ else
+ fail 'Invalid manifest, expecting Hash, Array, file name/task or
proc/method.'
+ end
+ end
+
+ attr_reader :sections
+
+ def main
+ sections.first
+ end
+
+ include Enumerable
+
+ def each(&block)
+ @sections.each(&block)
+ end
+
+ def to_s
+ @sections.map { |section|
+ keys = section.keys
+ keys.unshift('Name') if keys.delete('Name')
+ lines = keys.map { |key| manifest_wrap_at_72("#{key}:
#{section[key]}") }
+ lines + ['']
+ }.flatten.join("\n")
+ end
+
+ private
+
+ def manifest_wrap_at_72(line)
+ return [line] if line.size < 72
+ [ line[0..70] ] + manifest_wrap_at_72(' ' + line[71..-1])
+ end
+
+ end
+
+
+ # Adds support for MANIFEST.MF and other META-INF files.
+ module WithManifest #:nodoc:
+
+ class << self
+ def included(base)
+ base.class_eval do
+ alias :initialize_without_manifest :initialize
+ alias :initialize :initialize_with_manifest
+ end
end
end
@@ -124,9 +146,10 @@
# Tempfiles gets deleted on garbage collection, so we're going
to hold on to it
# through instance variable not closure variable.
Tempfile.open 'MANIFEST.MF' do |@manifest_tmp|
- lines = String === manifest || Rake::Task === manifest ?
- WithManifest.manifest_lines_from(File.read(manifest.to_s)) :
WithManifest.manifest_lines_from(manifest)
- @manifest_tmp.write((MANIFEST_HEADER + lines).join("\n"))
+ self.manifest = File.read(manifest.to_s) if String ===
manifest || Rake::Task === manifest
+ self.manifest = Manifest.new(manifest) unless Manifest ===
manifest
+ @manifest_tmp.write Manifest::STANDARD_HEADER
+ @manifest_tmp.write manifest.to_s
@manifest_tmp.write "\n"
path('META-INF').include @manifest_tmp.path, :as=>'MANIFEST.MF'
end
@@ -409,15 +432,15 @@
file(path_to(component[:path],
component[:artifact].to_s.pathmap('%f')) => component[:artifact]) do |task|
mkpath task.to_s.pathmap('%d'), :verbose => false
cp component[:artifact].to_s, task.to_s, :verbose => false
- WithManifest.update_manifest(task) do |sections|
- class_path = sections.first['Class-Path'].to_s.split
+ Manifest.update_manifest(task) do |manifest|
+ class_path = manifest.main['Class-Path'].to_s.split
included_libs = class_path.map { |fn| fn.pathmap('%f') }
Zip::ZipFile.foreach(task.to_s) do |entry|
included_libs << entry.name.pathmap('%f') if entry.file? &&
entry.name =~ /^WEB-INF\/lib\/[^\/]+$/
end
# Include all other libraries in the classpath.
class_path += libs_classpath(component).reject { |path|
included_libs.include?(File.basename(path)) }
- sections.first['Class-Path'] = class_path.join(' ')
+ manifest.main['Class-Path'] = class_path.join(' ')
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=646061&r1=646060&r2=646061&view=diff
==============================================================================
--- incubator/buildr/trunk/spec/java_packaging_spec.rb (original)
+++ incubator/buildr/trunk/spec/java_packaging_spec.rb Tue Apr 8 13:31:32 2008
@@ -54,7 +54,9 @@
shared_examples_for 'package with manifest' do
- @long_line = 'No line may be longer than 72 bytes (not characters), in its
UTF8-encoded form. If a value would make the initial line longer than this, it
should be continued on extra lines (each starting with a single SPACE).'
+ before do
+ @long_line = 'No line may be longer than 72 bytes (not characters), in its
UTF8-encoded form. If a value would make the initial line longer than this, it
should be continued on extra lines (each starting with a single SPACE).'
+ end
def package_with_manifest(manifest = nil)
packaging = @packaging
@@ -67,15 +69,15 @@
def inspect_manifest
package = project('foo').package(@packaging)
package.invoke
- yield Buildr::Packaging::Java::WithManifest.from_file(package)
+ yield Buildr::Packaging::Java::Manifest.from_zip(package)
end
it 'should include default header when no options specified' do
ENV['USER'] = 'MysteriousJoe'
package_with_manifest # Nothing for default.
- inspect_manifest do |sections|
- sections.size.should be(1)
- sections.first.should == {
+ inspect_manifest do |manifest|
+ manifest.sections.size.should be(1)
+ manifest.main.should == {
'Manifest-Version' =>'1.0',
'Created-By' =>'Buildr',
'Implementation-Title' =>@project.name,
@@ -96,12 +98,12 @@
it 'should map manifest from hash' do
package_with_manifest 'Foo'=>1, :bar=>'Bar'
- inspect_manifest do |sections|
- sections.size.should be(1)
- sections.first['Manifest-Version'].should eql('1.0')
- sections.first['Created-By'].should eql('Buildr')
- sections.first['Foo'].should eql('1')
- sections.first['bar'].should eql('Bar')
+ inspect_manifest do |manifest|
+ manifest.sections.size.should be(1)
+ manifest.main['Manifest-Version'].should eql('1.0')
+ manifest.main['Created-By'].should eql('Buildr')
+ manifest.main['Foo'].should eql('1')
+ manifest.main['bar'].should eql('Bar')
end
end
@@ -109,24 +111,24 @@
package_with_manifest 'Foo'=>1, :bar=>'Bar'
package = project('foo').package(@packaging)
package.invoke
- Zip::ZipFile.open(package.to_s) { |zip|
zip.file.read('META-INF/MANIFEST.MF').should =~
/#{Buildr::Packaging::Java::WithManifest::MANIFEST_LINE_SEP}$/ }
+ Zip::ZipFile.open(package.to_s) { |zip|
zip.file.read('META-INF/MANIFEST.MF').should =~
/#{Buildr::Packaging::Java::Manifest::LINE_SEPARATOR}$/ }
end
it 'should break hash manifest lines longer than 72 characters using
continuations' do
package_with_manifest 'foo'=>@long_line
package = project('foo').package(@packaging)
- inspect_manifest do |sections|
- sections.first['foo'].should == @long_line
+ inspect_manifest do |manifest|
+ manifest.main['foo'].should == @long_line
end
end
it 'should map manifest from array' do
package_with_manifest [ { :foo=>'first' }, { :bar=>'second' } ]
- inspect_manifest do |sections|
- sections.size.should be(2)
- sections.first['Manifest-Version'].should eql('1.0')
- sections.first['foo'].should eql('first')
- sections.last['bar'].should eql('second')
+ inspect_manifest do |manifest|
+ manifest.sections.size.should be(2)
+ manifest.main['Manifest-Version'].should eql('1.0')
+ manifest.main['foo'].should eql('first')
+ manifest.sections.last['bar'].should eql('second')
end
end
@@ -140,8 +142,8 @@
it 'should break array manifest lines longer than 72 characters using
continuations' do
package_with_manifest ['foo'=>@long_line]
package = project('foo').package(@packaging)
- inspect_manifest do |sections|
- sections.first['foo'].should == @long_line
+ inspect_manifest do |manifest|
+ manifest.main['foo'].should == @long_line
end
end
@@ -149,27 +151,27 @@
package_with_manifest [ {}, { 'Name'=>'first', :Foo=>'first',
:bar=>'second' } ]
package = project('foo').package(@packaging)
package.invoke
- inspect_manifest do |sections|
- sections[1]["Name"].should == "first"
+ inspect_manifest do |manifest|
+ manifest.sections[1]["Name"].should == "first"
end
end
it 'should create manifest from proc' do
package_with_manifest lambda { 'Meta: data' }
- inspect_manifest do |sections|
- sections.size.should be(1)
- sections.first['Manifest-Version'].should eql('1.0')
- sections.first['Meta'].should eql('data')
+ inspect_manifest do |manifest|
+ manifest.sections.size.should be(1)
+ manifest.main['Manifest-Version'].should eql('1.0')
+ manifest.main['Meta'].should eql('data')
end
end
it 'should create manifest from file' do
write 'MANIFEST.MF', 'Meta: data'
package_with_manifest 'MANIFEST.MF'
- inspect_manifest do |sections|
- sections.size.should be(1)
- sections.first['Manifest-Version'].should eql('1.0')
- sections.first['Meta'].should eql('data')
+ inspect_manifest do |manifest|
+ manifest.sections.size.should be(1)
+ manifest.main['Manifest-Version'].should eql('1.0')
+ manifest.main['Meta'].should eql('data')
end
end
@@ -178,10 +180,10 @@
write task.to_s, 'Meta: data'
end
package_with_manifest 'MANIFEST.MF'
- inspect_manifest do |sections|
- sections.size.should be(1)
- sections.first['Manifest-Version'].should eql('1.0')
- sections.first['Meta'].should eql('data')
+ inspect_manifest do |manifest|
+ manifest.sections.size.should be(1)
+ manifest.main['Manifest-Version'].should eql('1.0')
+ manifest.main['Meta'].should eql('data')
end
end
@@ -190,7 +192,7 @@
mkpath 'target/classes'
packaging = @packaging
define('foo', :version=>'1.0') { package(packaging).with
:manifest=>{'Foo'=>'data'} }
- inspect_manifest { |sections| sections.first['Foo'].should eql('data') }
+ inspect_manifest { |manifest| manifest.main['Foo'].should eql('data') }
end
it 'should include META-INF directory' do
@@ -564,8 +566,8 @@
File.open('tmp.zip', 'wb') do |tmp|
tmp.write ear.file.read(package)
end
- sections = Buildr::Packaging::Java::WithManifest.from_file('tmp.zip')
- yield sections.first['Class-Path'].to_s.split(' ')
+ manifest = Buildr::Packaging::Java::Manifest.from_zip('tmp.zip')
+ yield manifest.main['Class-Path'].to_s.split(' ')
end
end
@@ -624,8 +626,8 @@
inspect_ear { |files| files.should include('lib/one-1.0.jar',
'ejb/two-1.0.jar') }
-
Buildr::Packaging::Java::WithManifest.from_file(project('one').package(:jar)).first['Class-Path'].should
be_nil
-
Buildr::Packaging::Java::WithManifest.from_file(project('two').package(:jar)).first['Class-Path'].should
be_nil
+
Buildr::Packaging::Java::Manifest.from_zip(project('one').package(:jar)).main['Class-Path'].should
be_nil
+
Buildr::Packaging::Java::Manifest.from_zip(project('two').package(:jar)).main['Class-Path'].should
be_nil
inspect_classpath 'ejb/two-1.0.jar' do |classpath|
classpath.should include('../lib/one-1.0.jar')