Class: Warbler::Jar

Inherits:
Object
  • Object
show all
Includes:
PathmapHelper, RakeHelper
Defined in:
lib/warbler/jar.rb

Overview

Class that holds the files that will be stored in the jar file. The #files attribute contains a hash of pathnames inside the jar file to their contents. Contents can be one of:

  • nil representing a directory entry

  • Any object responding to read representing an in-memory blob

  • A String filename pointing to a file on disk

Direct Known Subclasses

War

Constant Summary collapse

DEFAULT_MANIFEST =
%{Manifest-Version: 1.0\nCreated-By: Warbler #{Warbler::VERSION}\n\n}

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods included from RakeHelper

extended, included

Methods included from PathmapHelper

#apply_pathmaps

Constructor Details

#initializeJar

Returns a new instance of Jar.



28
29
30
# File 'lib/warbler/jar.rb', line 28

def initialize
  @files = {}
end

Instance Attribute Details

#app_filelistObject (readonly)

Returns the value of attribute app_filelist.



26
27
28
# File 'lib/warbler/jar.rb', line 26

def app_filelist
  @app_filelist
end

#filesObject (readonly)

Returns the value of attribute files.



25
26
27
# File 'lib/warbler/jar.rb', line 25

def files
  @files
end

Instance Method Details

#add_init_file(config) ⇒ Object

Add init.rb file to the war file.



178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
# File 'lib/warbler/jar.rb', line 178

def add_init_file(config)
  if config.init_contents
    contents = ''
    config.init_contents.each do |file|
      if file.respond_to?(:read)
        contents << file.read
      elsif File.extname(file) == '.erb'
        contents << expand_erb(file, config).read
      else
        contents << File.read(file)
      end
    end
    @files[config.init_filename] = StringIO.new(contents)
  end
end

#add_manifest(config = nil) ⇒ Object

Add a manifest file either from config or by making a default manifest.



101
102
103
104
105
106
107
108
109
# File 'lib/warbler/jar.rb', line 101

def add_manifest(config = nil)
  unless @files.keys.detect{|k| k =~ /^META-INF\/MANIFEST\.MF$/i}
    if config && config.manifest_file
      @files['META-INF/MANIFEST.MF'] = config.manifest_file
    else
      @files['META-INF/MANIFEST.MF'] = StringIO.new(DEFAULT_MANIFEST)
    end
  end
end

#add_with_pathmaps(config, f, map_type) ⇒ Object



194
195
196
# File 'lib/warbler/jar.rb', line 194

def add_with_pathmaps(config, f, map_type)
  @files[apply_pathmaps(config, f, map_type)] = f
end

#apply(config) ⇒ Object

Apply the information in a Warbler::Config object in order to look for files to put into this war file.



68
69
70
71
72
73
74
75
76
# File 'lib/warbler/jar.rb', line 68

def apply(config)
  find_application_files(config)
  find_java_libs(config)
  find_java_classes(config)
  find_gems_files(config)
  add_manifest(config)
  add_init_file(config)
  apply_traits(config)
end

#apply_traits(config) ⇒ Object

Invoke a hook to allow the project traits to add or modify the archive contents.



96
97
98
# File 'lib/warbler/jar.rb', line 96

def apply_traits(config)
  config.update_archive(self)
end

#compile(config) ⇒ Object



37
38
39
40
41
42
43
44
# File 'lib/warbler/jar.rb', line 37

def compile(config)
  # Compiling all Ruby files we can find -- do we need to allow an
  # option to configure what gets compiled?
  return if config.compiled_ruby_files.nil? || config.compiled_ruby_files.empty?

  run_javac(config, config.compiled_ruby_files)
  replace_compiled_ruby_files(config, config.compiled_ruby_files)
end

#contents(entry) ⇒ Object



32
33
34
35
# File 'lib/warbler/jar.rb', line 32

def contents(entry)
  file = files[entry]
  file.respond_to?(:read) ? file.read : File.open(file) {|f| f.read }
end

#create(config_or_path) ⇒ Object

Create the jar or war file. The single argument can either be a Warbler::Config or a filename of the file to create.



80
81
82
83
84
85
86
87
88
89
90
91
92
93
# File 'lib/warbler/jar.rb', line 80

def create(config_or_path)
  path = config_or_path
  if Warbler::Config === config_or_path
    path = "#{config_or_path.jar_name}.#{config_or_path.jar_extension}"
    path = File.join(config_or_path.autodeploy_dir, path) if config_or_path.autodeploy_dir
  end
  rm_f path
  ensure_directory_entries
  puts "Creating #{path}"
  if Warbler::Config === config_or_path
    @files.delete("#{config_or_path.jar_name}/#{path}")
  end
  create_jar path, @files
end

#create_jar(jar_path, entries) ⇒ Object



219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
# File 'lib/warbler/jar.rb', line 219

def create_jar(jar_path, entries)
  Zip::ZipFile.open(jar_path, Zip::ZipFile::CREATE) do |zipfile|
    entries.keys.sort.each do |entry|
      src = entries[entry]
      if src.respond_to?(:read)
        zipfile.get_output_stream(entry) {|f| f << src.read }
      elsif src.nil? || File.directory?(src)
        if File.symlink?(entry) && ! defined?(JRUBY_VERSION)
          $stderr.puts "directory symlinks are not followed unless using JRuby; " + 
                       "#{entry.inspect} contents not in archive" 
        end
        zipfile.mkdir(entry.dup) # in case it's frozen rubyzip 0.9.6.1 workaround
      elsif File.symlink?(src)
        zipfile.get_output_stream(entry) { |f| f << File.read(src) }
      else
        zipfile.add(entry, src)
      end
    end
  end
end

#ensure_directory_entriesObject



209
210
211
212
213
214
215
216
217
# File 'lib/warbler/jar.rb', line 209

def ensure_directory_entries
  files.select {|k,v| !v.nil? }.each do |k,v|
    dir = File.dirname(k)
    while dir != "." && !files.has_key?(dir)
      files[dir] = nil
      dir = File.dirname(dir)
    end
  end
end

#entry_in_jar(jar, entry) ⇒ Object



240
241
242
243
244
# File 'lib/warbler/jar.rb', line 240

def entry_in_jar(jar, entry)
  Zip::ZipFile.open(jar) do |zf|
    zf.get_input_stream(entry) {|io| StringIO.new(io.read) }
  end
end

#erb_binding(config) ⇒ Object



204
205
206
207
# File 'lib/warbler/jar.rb', line 204

def erb_binding(config)
  webxml = config.webxml
  binding
end

#expand_erb(file, config) ⇒ Object



198
199
200
201
202
# File 'lib/warbler/jar.rb', line 198

def expand_erb(file, config)
  require 'erb'
  erb = ERB.new(File.open(file) {|f| f.read })
  StringIO.new(erb.result(erb_binding(config)))
end

#find_application_files(config) ⇒ Object

Add all application directories and files to the archive.



163
164
165
166
167
168
169
170
171
172
173
174
175
# File 'lib/warbler/jar.rb', line 163

def find_application_files(config)
  config.dirs.select do |d|
    exists = File.directory?(d)
    $stderr.puts "warning: application directory `#{d}' does not exist or is not a directory; skipping" unless exists
    exists
  end.each do |d|
    @files[apply_pathmaps(config, d, :application)] = nil
  end
  @app_filelist = FileList[*(config.dirs.map{|d| "#{d}/**/*"})]
  @app_filelist.include *(config.includes.to_a)
  @app_filelist.exclude *(config.excludes.to_a)
  @app_filelist.map {|f| add_with_pathmaps(config, f, :application) }
end

#find_gems_files(config) ⇒ Object

Add gems to WEB-INF/gems



122
123
124
# File 'lib/warbler/jar.rb', line 122

def find_gems_files(config)
  config.gems.each {|gem, version| find_single_gem_files(config, gem, version) }
end

#find_java_classes(config) ⇒ Object

Add java classes to WEB-INF/classes.



117
118
119
# File 'lib/warbler/jar.rb', line 117

def find_java_classes(config)
  config.java_classes.map {|f| add_with_pathmaps(config, f, :java_classes) }
end

#find_java_libs(config) ⇒ Object

Add java libraries to WEB-INF/lib.



112
113
114
# File 'lib/warbler/jar.rb', line 112

def find_java_libs(config)
  config.java_libs.map {|lib| add_with_pathmaps(config, lib, :java_libs) }
end

#find_single_gem_files(config, gem_pattern, version = nil) ⇒ Object

Add a single gem to WEB-INF/gems



127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
# File 'lib/warbler/jar.rb', line 127

def find_single_gem_files(config, gem_pattern, version = nil)
  if Gem::Specification === gem_pattern
    spec = gem_pattern
  else
    gem = case gem_pattern
          when Gem::Dependency
            gem_pattern
          else
            Gem::Dependency.new(gem_pattern, Gem::Requirement.create(version))
          end

    # skip development dependencies
    return if gem.respond_to?(:type) and gem.type != :runtime

    # Deal with deprecated Gem.source_index and #search
    matched = gem.respond_to?(:to_spec) ? [gem.to_spec] : Gem.source_index.search(gem)
    fail "gem '#{gem}' not installed" if matched.empty?
    spec = matched.last
  end

  full_gem_path = Pathname.new(spec.full_gem_path)

  # skip gems whose full_gem_path does not exist
  ($stderr.puts "warning: skipping #{spec.name} (#{full_gem_path.to_s} does not exist)" ; return) unless full_gem_path.exist?

  @files[apply_pathmaps(config, "#{spec.full_name}.gemspec", :gemspecs)] = StringIO.new(spec.to_ruby)
  FileList["#{full_gem_path.to_s}/**/*"].each do |src|
    f = Pathname.new(src).relative_path_from(full_gem_path).to_s
    next if config.gem_excludes && config.gem_excludes.any? {|rx| f =~ rx }
    @files[apply_pathmaps(config, File.join(spec.full_name, f), :gems)] = src
  end

  spec.dependencies.each {|dep| find_single_gem_files(config, dep) } if config.gem_dependencies
end

#replace_compiled_ruby_files(config, compiled_ruby_files) ⇒ Object



56
57
58
59
60
61
62
63
64
# File 'lib/warbler/jar.rb', line 56

def replace_compiled_ruby_files(config, compiled_ruby_files)
  # Exclude the rb files and recreate them. This
  # prevents the original contents being used.
  config.excludes += compiled_ruby_files

  compiled_ruby_files.each do |ruby_source|
    files[apply_pathmaps(config, ruby_source, :application)] = StringIO.new("load __FILE__.sub(/\.rb$/, '.class')")
  end
end

#run_javac(config, compiled_ruby_files) ⇒ Object



46
47
48
49
50
51
52
53
54
# File 'lib/warbler/jar.rb', line 46

def run_javac(config, compiled_ruby_files)
  if config.webxml && config.webxml.context_params.has_key?('jruby.compat.version')
    compat_version = "--#{config.webxml.jruby.compat.version}"
  else
    compat_version = ''
  end
  # Need to use the version of JRuby in the application to compile it
  %x{java -classpath #{config.java_libs.join(File::PATH_SEPARATOR)} org.jruby.Main #{compat_version} -S jrubyc \"#{compiled_ruby_files.join('" "')}\"}
end