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.



170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
# File 'lib/warbler/jar.rb', line 170

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.



93
94
95
96
97
98
99
100
101
# File 'lib/warbler/jar.rb', line 93

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



186
187
188
# File 'lib/warbler/jar.rb', line 186

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.



63
64
65
66
67
68
69
70
71
# File 'lib/warbler/jar.rb', line 63

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.



88
89
90
# File 'lib/warbler/jar.rb', line 88

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.



75
76
77
78
79
80
81
82
83
84
85
# File 'lib/warbler/jar.rb', line 75

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}"
  create_jar path, @files
end

#create_jar(jar_path, entries) ⇒ Object



211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
# File 'lib/warbler/jar.rb', line 211

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



201
202
203
204
205
206
207
208
209
# File 'lib/warbler/jar.rb', line 201

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



232
233
234
235
236
# File 'lib/warbler/jar.rb', line 232

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



196
197
198
199
# File 'lib/warbler/jar.rb', line 196

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

#expand_erb(file, config) ⇒ Object



190
191
192
193
194
# File 'lib/warbler/jar.rb', line 190

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.



155
156
157
158
159
160
161
162
163
164
165
166
167
# File 'lib/warbler/jar.rb', line 155

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



114
115
116
# File 'lib/warbler/jar.rb', line 114

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.



109
110
111
# File 'lib/warbler/jar.rb', line 109

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.



104
105
106
# File 'lib/warbler/jar.rb', line 104

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



119
120
121
122
123
124
125
126
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
# File 'lib/warbler/jar.rb', line 119

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



51
52
53
54
55
56
57
58
59
# File 'lib/warbler/jar.rb', line 51

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("require __FILE__.sub(/\.rb$/, '.class')")
  end
end

#run_javac(config, compiled_ruby_files) ⇒ Object



46
47
48
49
# File 'lib/warbler/jar.rb', line 46

def run_javac(config, compiled_ruby_files)
  # 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 -S jrubyc \"#{compiled_ruby_files.join('" "')}\"}
end