Class: TorqueBox::CLI::Jar

Inherits:
Object
  • Object
show all
Defined in:
core/lib/torquebox/cli/jar.rb

Direct Known Subclasses

War

Constant Summary

DEFAULT_INIT =
"require 'torquebox-core'; \
TorqueBox::CLI::Archive.new(ARGV).run;"

Instance Method Summary (collapse)

Constructor Details

- (Jar) initialize

Returns a new instance of Jar



28
29
30
31
# File 'core/lib/torquebox/cli/jar.rb', line 28

def initialize
  @logger = org.projectodd.wunderboss.WunderBoss.logger('TorqueBox')
  @classpath = []
end

Instance Method Details

- (Object) add_app_files(jar_builder, options)



184
185
186
187
188
189
190
191
192
193
194
195
# File 'core/lib/torquebox/cli/jar.rb', line 184

def add_app_files(jar_builder, options)
  @logger.trace("Adding application files to jar...")
  exclude = [Regexp.new("^[^/]*\.(jar|war)")]
  if options[:exclude]
    exclude += options[:exclude].map { |e| Regexp.new("^#{e}") }
  end
  add_files(jar_builder,
            :file_prefix => Dir.pwd,
            :pattern => "/**/{*,\.*manifest*}",
            :jar_prefix => "app",
            :exclude => exclude)
end

- (Object) add_bundler_files(jar_builder, tmpdir, bundle_without)



197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
# File 'core/lib/torquebox/cli/jar.rb', line 197

def add_bundler_files(jar_builder, tmpdir, bundle_without)
  @logger.trace("Adding bundler files to jar...")
  unless File.exist?(ENV['BUNDLE_GEMFILE'] || 'Gemfile')
    @logger.info("No Gemfile found - skipping gem dependencies")
    return {}
  end
  @logger.info("Bundling gem dependencies")
  require 'bundler'

  copy_bundle_config(tmpdir)

  vendor_dir_exists = File.exist?('vendor')
  cache_dir_exists = File.exist?('vendor/cache')
  bundle_dir_exists = File.exist?('vendor/bundle')
  already_cached = Dir.glob('vendor/cache/*.gem').count > 0
  already_bundled = Pathname.new(Bundler.settings.path).relative?

  lockfile = Bundler.default_lockfile
  original_lockfile = File.exist?(lockfile) ? File.read(lockfile) : nil

  cache_gems(tmpdir) unless already_cached
  bundle_gems(tmpdir, bundle_without) unless already_bundled
  copy_cached_gems(tmpdir) unless already_cached
  copy_and_restore_lockfile(tmpdir, lockfile, original_lockfile)

  add_files(jar_builder,
            :file_prefix => tmpdir,
            :pattern => "/{**/*,.bundle/**/*}",
            :jar_prefix => "app",
            :exclude => TorqueBox::Jars.list.map { |j| File.basename(j)  })
  Gem.path.each do |prefix|
    add_files(jar_builder,
              :file_prefix => prefix,
              :pattern => "/**/bundler-#{Bundler::VERSION}{*,/**/*}",
              :jar_prefix => "jruby/lib/ruby/gems/shared")
  end
ensure
  FileUtils.rm_rf('vendor/bundle') unless bundle_dir_exists
  FileUtils.rm_rf('vendor/cache') unless cache_dir_exists
  FileUtils.rm_rf('vendor') unless vendor_dir_exists
end

- (Object) add_default_gems(jar_builder)



169
170
171
172
173
174
175
176
177
178
179
180
181
182
# File 'core/lib/torquebox/cli/jar.rb', line 169

def add_default_gems(jar_builder)
  default_spec_suffix = "specifications/default"
  default_spec_dir = "#{Gem.default_dir}/#{default_spec_suffix}"
  jar_prefix = "jruby/lib/ruby/gems/shared"
  Dir.glob("#{default_spec_dir}/*.gemspec").each do |file|
    jar_builder.add_file(File.join(jar_prefix, default_spec_suffix,
                                   File.basename(file)), file)
    gem_full_name = File.basename(file, ".*")
    add_files(jar_builder,
              :file_prefix => "#{Gem.default_dir}/gems/#{gem_full_name}",
              :pattern => "/**/*",
              :jar_prefix => "#{jar_prefix}/gems/#{gem_full_name}")
  end
end

- (Object) add_files(jar_builder, options)



301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
# File 'core/lib/torquebox/cli/jar.rb', line 301

def add_files(jar_builder, options)
  prefix = options[:file_prefix]
  prefix += '/' unless prefix.end_with?('/')
  Dir.glob(File.join(prefix, options[:pattern])).each do |file|
    suffix = file.sub(prefix, '')
    excludes = [options[:exclude]].compact.flatten
    next if excludes.any? do |exclude|
      if exclude.is_a?(Regexp)
        exclude =~ suffix
      else
        suffix.include?(exclude)
      end
    end
    next if suffix.include?("tmptorqueboxjar")
    in_jar_name = options[:jar_prefix] ? File.join(options[:jar_prefix], suffix) : suffix
    jar_builder.add_file(in_jar_name, file)
  end
end

- (Object) add_jar(jar_builder, jar)



283
284
285
286
287
288
# File 'core/lib/torquebox/cli/jar.rb', line 283

def add_jar(jar_builder, jar)
  @logger.debug("Adding jar {}", jar)
  jar_name = "jars/#{File.basename(jar)}"
  @classpath << "${extract_root}/#{jar_name}"
  jar_builder.add_file(jar_name, jar)
end

- (Object) add_jruby_files(jar_builder)



149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
# File 'core/lib/torquebox/cli/jar.rb', line 149

def add_jruby_files(jar_builder)
  @logger.trace("Adding JRuby files to jar...")
  rb_config = RbConfig::CONFIG
  add_files(jar_builder,
            :file_prefix => rb_config["prefix"],
            :pattern => "/*",
            :jar_prefix => "jruby")
  add_files(jar_builder,
            :file_prefix => rb_config["libdir"],
            :pattern => "/**/*",
            :jar_prefix => "jruby/lib",
            :exclude => ["jruby.jar", "ruby/gems/shared"])
  add_files(jar_builder,
            :file_prefix => rb_config["bindir"],
            :pattern => "/*",
            :jar_prefix => "jruby/bin")
  add_jar(jar_builder, "#{rb_config['libdir']}/jruby.jar")
  add_default_gems(jar_builder)
end

- (Object) add_torquebox_files(jar_builder)



290
291
292
293
294
295
296
297
298
299
# File 'core/lib/torquebox/cli/jar.rb', line 290

def add_torquebox_files(jar_builder)
  TorqueBox::Jars.list.each do |jar|
    if File.basename(jar) =~ /^wunderboss-(rack|ruby).*?\.jar$/
      add_jar(jar_builder, jar)
    else
      @logger.debug("Shading jar {}", jar)
      jar_builder.shade_jar(jar)
    end
  end
end

- (Object) app_properties(env, init)



333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
# File 'core/lib/torquebox/cli/jar.rb', line 333

def app_properties(env, init)
  env_str = env.map do |key, value|
    "ENV['#{key}'] ||= '#{value}';"
  end.join(' ')
  classpath_str = @classpath.join(':')

  <<-EOS
language=ruby
extract_paths=app/:jruby/:jars/
root=${extract_root}/app
classpath=#{classpath_str}
init=ENV['BUNDLE_GEMFILE'] = nil; \
#{env_str} \
require "bundler/setup"; \
#{init}; \
require "torquebox/spec_helpers"; \
TorqueBox::SpecHelpers.booted
EOS
end

- (Object) available_options



48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
# File 'core/lib/torquebox/cli/jar.rb', line 48

def available_options
  defaults = option_defaults
  [{
     :name => :destination,
     :switch => '--destination PATH',
     :description => "Destination directory for the jar file (default: #{defaults[:destination]})"
   },
   {
     :name => :jar_name,
     :switch => '--name NAME',
     :description => "Name of the jar file (default: #{defaults[:jar_name]})"
   },
   {
     :name => :include_jruby,
     :switch => '--[no-]include-jruby',
     :description => "Include JRuby in the jar (default: #{defaults[:include_jruby]})"
   },
   {
     :name => :bundle_gems,
     :switch => '--[no-]bundle-gems',
     :description => "Bundle gem dependencies in the jar (default: #{defaults[:bundle_gems]})"
   },
   {
     :name => :bundle_without,
     :switch => '--bundle-without GROUPS',
     :description => "Bundler groups to skip (default: #{defaults[:bundle_without]})",
     :type => Array
   },
   {
     :name => :main,
     :switch => '--main MAIN',
     :description => 'File to require to bootstrap the application (if not given, assumes a web app)'
   },
   {
     :name => :exclude,
     :switch => '--exclude EXCLUDES',
     :description => 'File paths to exclude from bundled jar',
     :type => Array
   }]
end

- (Object) bundle_gems(tmpdir, bundle_without)



254
255
256
257
258
259
260
261
262
263
264
265
266
# File 'core/lib/torquebox/cli/jar.rb', line 254

def bundle_gems(tmpdir, bundle_without)
  install_options = %W(--local --path vendor/bundle --no-cache)
  unless bundle_without.empty?
    install_options += %W(--without #{bundle_without.join(' ')})
  end
  eval_in_new_ruby <<-EOS
    ENV['BUNDLE_APP_CONFIG'] = "#{tmpdir}/.bundle"
    require 'bundler/cli'
    Bundler::CLI.start(['install'] + #{install_options.inspect})
  EOS
  FileUtils.mkdir_p("#{tmpdir}/vendor/bundle/jruby")
  FileUtils.cp_r('vendor/bundle/jruby', "#{tmpdir}/vendor/bundle/")
end

- (Object) cache_gems(tmpdir)



246
247
248
249
250
251
252
# File 'core/lib/torquebox/cli/jar.rb', line 246

def cache_gems(tmpdir)
  eval_in_new_ruby <<-EOS
    ENV['BUNDLE_APP_CONFIG'] = "#{tmpdir}/.bundle"
    require 'bundler/cli'
    Bundler::CLI.start(['cache', '--all'])
  EOS
end

- (Object) copy_and_restore_lockfile(tmpdir, lockfile, original_lockfile)



273
274
275
276
277
278
279
280
281
# File 'core/lib/torquebox/cli/jar.rb', line 273

def copy_and_restore_lockfile(tmpdir, lockfile, original_lockfile)
  new_lockfile = File.exist?(lockfile) ? File.read(lockfile) : nil
  FileUtils.cp(lockfile, "#{tmpdir}/Gemfile.lock") if new_lockfile
  if original_lockfile.nil? && !new_lockfile.nil?
    FileUtils.rm_f(lockfile)
  elsif original_lockfile != new_lockfile
    File.open(lockfile, 'w') { |f| f.write(original_lockfile) }
  end
end

- (Object) copy_bundle_config(tmpdir)



239
240
241
242
243
244
# File 'core/lib/torquebox/cli/jar.rb', line 239

def copy_bundle_config(tmpdir)
  if File.exist?('.bundle/config')
    FileUtils.mkdir_p("#{tmpdir}/.bundle")
    FileUtils.cp('.bundle/config', "#{tmpdir}/.bundle")
  end
end

- (Object) copy_cached_gems(tmpdir)



268
269
270
271
# File 'core/lib/torquebox/cli/jar.rb', line 268

def copy_cached_gems(tmpdir)
  FileUtils.mkdir_p("#{tmpdir}/vendor/cache")
  FileUtils.cp_r('vendor/cache', "#{tmpdir}/vendor/")
end

- (Object) eval_in_new_ruby(script)



320
321
322
323
324
325
326
327
328
329
330
331
# File 'core/lib/torquebox/cli/jar.rb', line 320

def eval_in_new_ruby(script)
  # Copy our environment to the new Ruby runtime
  config = org.jruby.RubyInstanceConfig.new
  config.environment = ENV
  config.current_directory = Dir.pwd
  ruby = org.jruby.Ruby.new_instance(config)
  unless %W(DEBUG TRACE).include?(TorqueBox::Logger.log_level)
    dev_null = PLATFORM =~ /mswin/ ? 'NUL' : '/dev/null'
    ruby.evalScriptlet("$stdout = File.open('#{dev_null}', 'w')")
  end
  ruby.evalScriptlet(script)
end

- (Object) option_defaults



37
38
39
40
41
42
43
44
45
46
# File 'core/lib/torquebox/cli/jar.rb', line 37

def option_defaults
  {
    :destination => '.',
    :jar_name => "#{File.basename(Dir.pwd)}.jar",
    :include_jruby => true,
    :bundle_gems => true,
    :bundle_without => %W(development test assets),
    :rackup => 'config.ru'
  }
end

- (Object) run(_argv, options)



107
108
109
110
111
112
113
114
115
116
117
118
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
# File 'core/lib/torquebox/cli/jar.rb', line 107

def run(_argv, options)
  options = option_defaults.merge(options)
  jar_path = File.expand_path(File.join(options[:destination], options[:jar_name]))
  @logger.debug("Creating jar with options {}", options.inspect)

  init = DEFAULT_INIT
  if options[:main]
    init = "ENV['TORQUEBOX_MAIN'] = '#{options[:main]}'; #{init}"
  end
  init = "ENV['TORQUEBOX_RACKUP'] = '#{options[:rackup]}'; #{init}"

  jar_builder = org.torquebox.core.JarBuilder.new
  jar_builder.add_manifest_attribute("Main-Class", "org.torquebox.core.TorqueBoxMain")
  jar_builder.add_string(TorqueBox::JAR_MARKER, "")

  add_torquebox_files(jar_builder)

  if options[:include_jruby]
    add_jruby_files(jar_builder)
  end

  add_app_files(jar_builder, options)

  if options[:bundle_gems]
    tmpdir = Dir.mktmpdir("tmptorqueboxjar", ".")
    add_bundler_files(jar_builder, tmpdir, options[:bundle_without])
  end

  jar_builder.add_string("META-INF/app.properties",
                         app_properties(options[:envvar] || {}, init))

  if File.exist?(jar_path)
    @logger.info("Removing {}", jar_path)
    FileUtils.rm_f(jar_path)
  end
  @logger.info("Writing {}", jar_path)
  jar_builder.create(jar_path)
  jar_path
ensure
  FileUtils.rm_rf(tmpdir) if tmpdir
end

- (Object) setup_parser(parser, options)



89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
# File 'core/lib/torquebox/cli/jar.rb', line 89

def setup_parser(parser, options)
  available_options.each do |opt|
    parser.on(*(opt.values_at(:short, :switch, :type, :description).compact)) do |arg|
      options[opt[:name]] = arg
    end
  end
  parser.on('--envvar KEY=VALUE',
            'Specify an environment variable to set before running the app') do |arg|
    key, value = arg.split('=')
    if key.nil? || value.nil?
      $stderr.puts "Error: Environment variables must be separated by '='"
      exit 1
    end
    options[:envvar] ||= {}
    options[:envvar][key] = value
  end
end

- (Object) usage_parameters



33
34
35
# File 'core/lib/torquebox/cli/jar.rb', line 33

def usage_parameters
  "[options]"
end