warbler 2.1.1 → 2.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: b68e1cba9a7e9e892eb9f5950fe177c07a7bba4f349813e7bb9b18e82ad9bbcc
4
- data.tar.gz: b0ed237291f26d1a79204499007d1527a97899214672474ef7cacd0aeb8591c4
3
+ metadata.gz: 34fe8d21840c8677062066d0df7979b427676ec18dc428e268fe7973f0bb320f
4
+ data.tar.gz: 5a68813d0b80ad5b705cb2cd1045ad65ef618c28ee3e9316ca179bf1f3522574
5
5
  SHA512:
6
- metadata.gz: 577dc3b4f393e6f4891e42806efdd64ab3ce8d3d222ff6b8ba6994a5f9376461ebcde493433d8875468cfacd8b63ec9fd058d26d8e6672e54458aa4120420e47
7
- data.tar.gz: d6a263d75de2a1f2f179751face07f9b922002a7bcaa7b0534289a2188067e52ac8131fd814014421008912cb183d3afb120a6d51566072c3c737a4ed90b05b4
6
+ metadata.gz: 9c84e0abec9a450e7fdbacd1eb88b0f17da8da95defb6092c476e30f4d90d72cf9413cea636716ffe71cbe170904b71766a5b4e80c7ceea68cda3856e9636675
7
+ data.tar.gz: b5c5aef56f17c17c2f6b30d1faa52664b72c685c82b96961efaee9fd5a5bc1a5561e0547bbd17d3824d0c61638bf3bac19c4d919d5b52b6f9070f2df0b125751
data/CHANGELOG.md CHANGED
@@ -1,3 +1,11 @@
1
+ ## 2.1.2
2
+
3
+ - #649: fix: further improve isolation of warbled jars/wars from host bundler configuration
4
+ - #648: fix: further improve isolation of warbled jars/wars from user/host gem paths
5
+ - #465: fix: remove duplication of bundler path gems in warbled jars/wars
6
+ - #331: fix: correct support for `gem_excludes` inside bundler git specs
7
+ - chore: relax jruby-rack requirement to allow compatibility with upcoming 2.0.x
8
+
1
9
  ## 2.1.1
2
10
 
3
11
  - #624, #635, #623: fix: ensure compatibility with JRuby 10.1
data/README.rdoc CHANGED
@@ -258,13 +258,7 @@ https://github.com/jruby/warbler/issues.
258
258
 
259
259
  === Common issues with executable wars
260
260
 
261
- If your app isn't working or starting up correctly:
262
-
263
- - <b>Missing Logging:</b>
264
- If your boot process is failing silently (or with a logging warning), try configuring the logger
265
- manually:
266
-
267
- java "-Dorg.eclipse.jetty.util.log.class=org.eclipse.jetty.util.log.StdErrLog" -jar my_app.war
261
+ If your app isn't working or starting up correctly:
268
262
 
269
263
  - <b>CompatVersion errors:</b>
270
264
  If you are getting <tt>java.lang.NoClassDefFoundError: org/jruby/CompatVersion</tt> errors at start-up
data/ext/WarMain.java CHANGED
@@ -304,22 +304,21 @@ public class WarMain extends JarMain {
304
304
 
305
305
  protected String locateExecutableScript(final String executable, final CharSequence envPreScript) {
306
306
  return ( envPreScript == null ? "" : envPreScript + " \n" ) +
307
- "begin\n" + // locate the executable within gemspecs :
308
- " require 'rubygems' unless defined?(Gem) \n" +
309
- " begin\n" + // add bundled gems to load path :
310
- " require 'bundler' \n" +
311
- " rescue LoadError\n" + // bundler not used
312
- " else\n" +
313
- " env = ENV['RAILS_ENV'] || ENV['RACK_ENV'] \n" + // init.rb sets ENV['RAILS_ENV'] ||= ...
314
- " env ? Bundler.setup(:default, env) : Bundler.setup(:default) \n" +
315
- " end if ENV_JAVA['warbler.bundler.setup'] != 'false' \n" + // java -Dwarbler.bundler.setup=false -jar my.war -S pry
316
- " exec = '"+ executable +"' \n" +
317
- " spec = Gem::Specification.find { |s| s.executables.include?(exec) } \n" +
318
- " spec ? spec.bin_file(exec) : nil \n" +
319
- // returns the full path to the executable
320
- "rescue SystemExit => e\n" +
321
- " e.status\n" +
322
- "end";
307
+ "begin\n" + // locate the executable within gemspecs :
308
+ " begin\n" + // add bundled gems to load path :
309
+ " require 'bundler' \n" +
310
+ " rescue LoadError\n" + // bundler not used
311
+ " else\n" +
312
+ " env = ENV['RAILS_ENV'] || ENV['RACK_ENV'] \n" + // init.rb sets ENV['RAILS_ENV'] ||= ...
313
+ " env ? Bundler.setup(:default, env) : Bundler.setup(:default) \n" +
314
+ " end if ENV_JAVA['warbler.bundler.setup'] != 'false' \n" + // java -Dwarbler.bundler.setup=false -jar my.war -S pry
315
+ " exec = '"+ executable +"' \n" +
316
+ " spec = Gem::Specification.find { |s| s.executables.include?(exec) } \n" +
317
+ " spec ? spec.bin_file(exec) : nil \n" +
318
+ // returns the full path to the executable
319
+ "rescue SystemExit => e\n" +
320
+ " e.status\n" +
321
+ "end";
323
322
  }
324
323
 
325
324
  protected void initJRubyScriptingEnv(Object scriptingContainer) throws Exception {
@@ -60,8 +60,10 @@ module Warbler
60
60
  # Whether to include dependent gems (default true)
61
61
  attr_accessor :gem_dependencies
62
62
 
63
- # Array of regular expressions matching relative paths in gems to
64
- # be excluded from the war. Default contains no exclusions.
63
+ # Array of regular expressions matching paths *inside* packed gems to be
64
+ # excluded from the archive. Paths are matched relative to each gem's root
65
+ # (for git-sourced gems: the repository checkout root). Default contains no
66
+ # exclusions.
65
67
  attr_accessor :gem_excludes
66
68
 
67
69
  # Whether to exclude **/*.log files (default is true)
data/lib/warbler/jar.rb CHANGED
@@ -219,7 +219,7 @@ module Warbler
219
219
  # OK if the gem does not exists as its un-packed on the "shared" path
220
220
  # ... at least gem spec.spec_file should exists although not crucial
221
221
  if JRUBY_VERSION != JRubyJars::VERSION
222
- warn "skipping #{spec.name} default gem (assuming its part of jruby-jars #{JRubyJars::VERSION})" unless silent?
222
+ warn "skipping #{spec.name} default gem (assuming its part of jruby-jars #{JRubyJars::VERSION})"
223
223
  end
224
224
  else
225
225
  warn "skipping #{spec.name} gem (#{full_gem_path.to_s} does not exist)"
@@ -1,4 +1 @@
1
1
  ENV['BUNDLE_WITHOUT'] = '<%= config.bundle_without.join(':') %>'
2
- <% if config.bundler[:frozen] -%>
3
- ENV['BUNDLE_FROZEN'] = '1'
4
- <% end -%>
@@ -4,10 +4,12 @@ ENV['GEM_HOME'] <%= config.override_gem_home ? '=' : '||=' %> File.expand_path(F
4
4
  ENV['GEM_HOME'] <%= config.override_gem_home ? '=' : '||=' %> File.expand_path(File.join('..', '..', '<%= config.relative_gem_path %>'), __FILE__)
5
5
  <% end -%>
6
6
  <% if config.override_gem_home -%>
7
- ENV['GEM_PATH'] = nil # RGs sets Gem.paths.path = Gem.default_path + [ GEM_HOME ]
7
+ <%# GEM_HOME (the packed gems) is always on Gem.path; adding only the runtime's own default %>
8
+ <%# gem dir (Ruby's "bundled gems") excludes host gem paths (e.g. Gem.user_dir aka ~/.gem) %>
9
+ ENV['GEM_PATH'] = Gem.default_dir
8
10
  <% end -%>
9
11
  <% if config.bundler && config.bundler[:gemfile_path] -%>
10
12
  ENV['BUNDLE_GEMFILE'] = File.expand_path(File.join('..', '..', '<%= config.bundler[:gemfile_path] %>'), __FILE__)
11
13
  <% end -%>
12
14
  <%# Ensure any cached paths are cleared; otherwise behaviour can be indeterminate if the paths have already been read %>
13
- # Gem.clear_paths
15
+ Gem.clear_paths
@@ -6,7 +6,9 @@ if $servlet_context.nil?
6
6
  else
7
7
  ENV['GEM_HOME'] <%= config.override_gem_home ? '=' : '||=' %> $servlet_context.getRealPath('<%= config.gem_path %>')
8
8
  <% if config.override_gem_home -%>
9
- ENV['GEM_PATH'] = nil
9
+ <%# GEM_HOME (the packed gems) is always on Gem.path; adding only the runtime's own default %>
10
+ <%# gem dir (Ruby's "bundled gems") excludes host gem paths (e.g. Gem.user_dir aka ~/.gem) %>
11
+ ENV['GEM_PATH'] = Gem.default_dir
10
12
  <% end -%>
11
13
  <% if config.bundler && config.bundler[:gemfile_path] -%>
12
14
  ENV['BUNDLE_GEMFILE'] ||= $servlet_context.getRealPath('/<%= config.bundler[:gemfile_path] %>')
@@ -14,6 +14,23 @@ module Warbler
14
14
  include PathmapHelper
15
15
  include BundlerHelper
16
16
 
17
+ # Bundler settings enforced in the packed application via a generated
18
+ # *.bundle/config*, the highest-precedence documented configuration level:
19
+ BUNDLE_CONFIG_DEFAULTS = {
20
+ # BUNDLE_VERSION: disable bundler's "auto-switch" to Gemfile.lock's BUNDLED WITH bundler version
21
+ # (bundler restarts the process to do so, which cannot work inside a servlet container or self-contained executable jar)
22
+ 'BUNDLE_VERSION' => 'system',
23
+ # BUNDLE_FROZEN: fail fast with a descriptive error on Gemfile vs Gemfile.lock drift instead of attempting
24
+ # a runtime re-resolution
25
+ 'BUNDLE_FROZEN' => 'true',
26
+ # BUNDLE_PATH__SYSTEM (path.system): pin bundler to the "system" gems - which are the packed gems, via
27
+ # GEM_HOME/GEM_PATH from *init.rb* - immune to a BUNDLE_PATH/BUNDLE_DEPLOYMENT leaking in from the host's
28
+ # environment or ~/.bundle/config
29
+ 'BUNDLE_PATH__SYSTEM' => 'true',
30
+ # BUNDLE_AUTO_INSTALL: never install gems at boot time, even if the host's environment or global config enables it
31
+ 'BUNDLE_AUTO_INSTALL' => 'false'
32
+ }.freeze
33
+
17
34
  def self.detect?
18
35
  File.exist?(ENV['BUNDLE_GEMFILE'] || 'Gemfile')
19
36
  end
@@ -36,6 +53,8 @@ module Warbler
36
53
  config.gem_dependencies = false # Bundler takes care of these
37
54
  config.bundler = {} if config.bundler == true
38
55
 
56
+ warn_on_bundler_version_mismatch
57
+
39
58
  bundler_specs.each do |spec|
40
59
  spec = to_spec(spec)
41
60
 
@@ -45,11 +64,12 @@ module Warbler
45
64
  config.bundler[:git_specs] << spec
46
65
  when ::Bundler::Source::Path
47
66
  unless bundler_source_is_warbled_gem_itself?(spec.source)
48
- if spec.source.path && spec.source.path.relative?
49
- # include (assuming) relative *[APP_ROOT]/gem/path*
50
- # NOTE: might be tuned to only add gemspec.files ...
67
+ if spec.source.path&.relative?
68
+ # pack the gem at its relative *[APP_ROOT]/gem/path* location - at runtime bundler resolves the path
69
+ # source relative to the packed Gemfile.
70
+ # Deliberately NOT also added to config.gems: bundler never materializes path gems from the gem
71
+ # repository; doing so would cause duplication.
51
72
  config.includes += FileList[File.join(spec.source.path, '**/*')]
52
- config.gems << spec # probably not really needed
53
73
  else
54
74
  warn("Bundler `path' components are not fully supported.\n" +
55
75
  "The `#{spec.full_name}' component was not bundled.\n" +
@@ -57,13 +77,12 @@ module Warbler
57
77
  end
58
78
  end
59
79
  else
60
- config.gems << spec
80
+ config.gems << spec unless spec.respond_to?(:default_gem?) && spec.default_gem?
61
81
  end
62
82
  end
63
83
  config.bundler[:gemfile] = ::Bundler.default_gemfile
64
84
  config.bundler[:gemfile_path] = apply_pathmaps(config, relative_from_pwd(::Bundler.default_gemfile), :application)
65
85
  config.bundler[:lockfile] = ::Bundler.default_lockfile
66
- config.bundler[:frozen] = ::Bundler.settings[:frozen]
67
86
  path = ::Bundler.settings[:path]
68
87
  config.excludes += [path, "#{path}/**/*"] if path
69
88
  config.init_contents << "#{config.warbler_templates}/bundler.erb"
@@ -73,42 +92,41 @@ module Warbler
73
92
  add_bundler_files(jar) if config.bundler
74
93
  end
75
94
 
76
- # Add Bundler Gemfiles and git repositories to the archive.
95
+ # Add Bundler Gemfiles, .bundle/config and git repositories to the archive.
77
96
  def add_bundler_files(jar)
78
97
  gemfile = relative_from_pwd(config.bundler[:gemfile])
79
98
  lockfile = relative_from_pwd(config.bundler[:lockfile])
99
+ bundle_config = File.join('.bundle', 'config')
100
+
80
101
  jar.files[apply_pathmaps(config, gemfile, :application)] = config.bundler[:gemfile].to_s
81
- if File.exist?(lockfile)
82
- jar.files[apply_pathmaps(config, lockfile, :application)] = config.bundler[:lockfile].to_s
83
- end
84
- if config.bundler[:git_specs]
85
- pathmap = "#{config.relative_gem_path}/bundler/gems/%p"
86
- pathmap.sub!(%r{^/+}, '')
87
- config.pathmaps.git = [pathmap]
88
- config.bundler[:git_specs].each do |spec|
89
- full_gem_path = Pathname.new(spec.full_gem_path)
90
-
91
- gem_relative_path = full_gem_path.relative_path_from(::Bundler.install_path)
92
- filenames = []
93
- gem_relative_path.each_filename { |f| filenames << f }
94
-
95
- exclude_gems = true
96
- unless filenames.empty?
97
- full_gem_path = Pathname.new(::Bundler.install_path) + filenames.first
98
- exclude_gems = false
99
- end
102
+ jar.files[apply_pathmaps(config, lockfile, :application)] = config.bundler[:lockfile].to_s if File.exist?(lockfile)
103
+ # NOTE: in-memory content must be an IO - jar creation treats plain Strings as source file paths
104
+ jar.files[apply_pathmaps(config, bundle_config, :application)] = StringIO.new(bundle_config_contents)
100
105
 
101
- if spec.groups.include?(:warbler_excluded)
102
- pattern = "#{full_gem_path.to_s}/**/#{spec.name}.gemspec" # #42: gemspec only to avert Bundler error
103
- else
104
- pattern = "#{full_gem_path.to_s}/**/*"
105
- end
106
+ add_bundler_git_specs(config.bundler[:git_specs], jar) if config.bundler[:git_specs]
107
+ end
106
108
 
107
- FileList[pattern].each do |src|
108
- f = Pathname.new(src).relative_path_from(full_gem_path).to_s
109
- next if exclude_gems && config.gem_excludes && config.gem_excludes.any? {|rx| f =~ rx }
110
- jar.files[apply_pathmaps(config, File.join(full_gem_path.basename, f), :git)] = src
111
- end
109
+ private
110
+
111
+ def add_bundler_git_specs(git_specs, jar)
112
+ config.pathmaps.git = ["#{config.relative_gem_path}/bundler/gems/%p".sub(%r{^/+}, '')]
113
+
114
+ # a git source checkout may contain multiple gems (spec.full_gem_path being a sub-directory) - bundler expects
115
+ # the complete repository checkout under bundler/gems/<repo>-<ref>, so pack from its root (once per repository,
116
+ # even when several specs share the checkout)
117
+ checkout_paths = git_specs.map do |spec|
118
+ full_gem_path = Pathname.new(spec.full_gem_path)
119
+ filenames = full_gem_path.relative_path_from(::Bundler.install_path).each_filename.to_a
120
+ filenames.empty? ? full_gem_path : Pathname.new(::Bundler.install_path) + filenames.first
121
+ end.uniq
122
+
123
+ checkout_paths.each do |checkout_path|
124
+ FileList["#{checkout_path.to_s}/**/*"].each do |src|
125
+ f = Pathname.new(src).relative_path_from(checkout_path).to_s
126
+ # NOTE: for git sources the excludes match relative to the packed repository checkout root (the gem root,
127
+ # except multi-gem repos)
128
+ next if config.gem_excludes && config.gem_excludes.any? { |rx| f =~ rx }
129
+ jar.files[apply_pathmaps(config, File.join(checkout_path.basename, f), :git)] = src
112
130
  end
113
131
  end
114
132
  end
@@ -121,17 +139,32 @@ module Warbler
121
139
  end
122
140
  end
123
141
 
124
- private
142
+ def warn_on_bundler_version_mismatch
143
+ lockfile = ::Bundler.default_lockfile
144
+ return unless lockfile && File.exist?(lockfile)
145
+ locked = ::Bundler::LockfileParser.new(File.read(lockfile)).bundler_version rescue nil
146
+ if locked && locked.to_s != ::Bundler::VERSION
147
+ warn("Gemfile.lock BUNDLED WITH (#{locked}) does not match the bundler running warbler (#{::Bundler::VERSION}).\n" +
148
+ "The packed application will boot with the default bundler of the packed JRuby (jruby-jars),\n" +
149
+ "consider re-generating Gemfile.lock with a matching bundler version.")
150
+ end
151
+ end
152
+
153
+ # Contents for the packed *.bundle/config*: only warbler's deployment settings, deliberately independent of the
154
+ # application's build-time bundler configuration.
155
+ def bundle_config_contents
156
+ require 'yaml'
157
+ settings = BUNDLE_CONFIG_DEFAULTS.dup
158
+ # frozen mode errors without a lockfile - do not force it upon applications packed without a Gemfile.lock
159
+ settings.delete('BUNDLE_FROZEN') if config.bundler[:frozen] == false || !File.exist?(config.bundler[:lockfile].to_s)
160
+ settings.to_yaml
161
+ end
125
162
 
126
163
  def bundler_specs
127
164
  bundle_without = config.bundle_without.map { |s| s.to_sym }
128
165
  definition = ::Bundler.definition
129
- all = definition.specs.to_a
130
166
  requested_groups = definition.groups - bundle_without
131
- requested = requested_groups.empty? ? [] : definition.specs_for(requested_groups).to_a
132
- excluded_git_specs = (all - requested).select { |spec| ::Bundler::Source::Git === spec.source }
133
- excluded_git_specs.each { |spec| spec.groups << :warbler_excluded }
134
- requested + excluded_git_specs
167
+ requested_groups.empty? ? [] : definition.specs_for(requested_groups).to_a
135
168
  end
136
169
 
137
170
  def bundler_source_is_warbled_gem_itself?(source)
@@ -32,10 +32,6 @@ module Warbler
32
32
  config.init_contents << "#{config.warbler_templates}/jar.erb"
33
33
  end
34
34
 
35
- def after_configure
36
- config.init_contents << StringIO.new("require 'rubygems' unless defined?(Gem)\n")
37
- end
38
-
39
35
  def update_archive(jar)
40
36
  unless config.manifest_file
41
37
  manifest = Warbler::Jar::DEFAULT_MANIFEST.chomp + "Main-Class: JarMain\n"
@@ -6,5 +6,5 @@
6
6
  #++
7
7
 
8
8
  module Warbler
9
- VERSION = "2.1.1"
9
+ VERSION = "2.1.2"
10
10
  end
data/lib/warbler_jar.jar CHANGED
Binary file
data/warble.rb CHANGED
@@ -21,7 +21,7 @@
21
21
  # Configure a new Warbler application assembly
22
22
  Warbler::Config.new(forced_traits: defined?(forced_traits) ? forced_traits : nil) do |config|
23
23
  # Features: additional options controlling how the jar is built.
24
- # Currently the following features are supported:
24
+ # Currently, the following features are supported:
25
25
  # - *gemjar*: package the gem repository in a jar file in WEB-INF/lib
26
26
  # - *executable*: embed a web server and make the war executable
27
27
  # - *runnable*: allows to run bin scripts e.g. `java -jar my.war -S rake -T`
@@ -101,7 +101,7 @@ Warbler::Config.new(forced_traits: defined?(forced_traits) ? forced_traits : nil
101
101
  # File extension for the archive. Defaults to either 'jar' or 'war'.
102
102
  # config.jar_extension = "jar"
103
103
 
104
- # Destionation for the created archive. Defaults to project's root directory.
104
+ # Destination for the created archive. Defaults to project's root directory.
105
105
  # config.autodeploy_dir = "dist/"
106
106
 
107
107
  # Name of the MANIFEST.MF template for the war file. Defaults to a simple
@@ -120,9 +120,9 @@ Warbler::Config.new(forced_traits: defined?(forced_traits) ? forced_traits : nil
120
120
  # When set it specify the bytecode version for compiled class files
121
121
  # config.bytecode_version = "1.8"
122
122
 
123
- # When set to true, Warbler will override the value of ENV['GEM_HOME'] even it
124
- # has already been set. When set to false it will use any existing value of
125
- # GEM_HOME if it is set.
123
+ # When set to true, Warbler will override the value of ENV['GEM_HOME'] even it has already been set.
124
+ # When set to false it will use any existing value of GEM_HOME if it is set. It's usually a bad idea to disable this;
125
+ # your built application will not be self-contained/isolated from the wider RubyGems environment of the machine.
126
126
  # config.override_gem_home = true
127
127
 
128
128
  # Specify executable
data/warbler.gemspec CHANGED
@@ -33,7 +33,7 @@ bundle up all of your application files for deployment to a Java environment.}
33
33
  gem.add_runtime_dependency 'rake', ['~> 13.0', '>= 13.0.3']
34
34
  gem.add_runtime_dependency 'rexml', '~> 3.0'
35
35
  gem.add_runtime_dependency 'jruby-jars', ['>= 9.4', '< 10.2']
36
- gem.add_runtime_dependency 'jruby-rack', ['>= 1.2.7', '< 1.4']
36
+ gem.add_runtime_dependency 'jruby-rack', ['>= 1.2.7', '< 2.1']
37
37
  gem.add_runtime_dependency 'rubyzip', ['>= 2.1.0', '< 4']
38
38
  gem.add_runtime_dependency 'ostruct', '~> 0.6.2'
39
39
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: warbler
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.1.1
4
+ version: 2.1.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Nick Sieger
@@ -72,7 +72,7 @@ dependencies:
72
72
  version: 1.2.7
73
73
  - - "<"
74
74
  - !ruby/object:Gem::Version
75
- version: '1.4'
75
+ version: '2.1'
76
76
  type: :runtime
77
77
  prerelease: false
78
78
  version_requirements: !ruby/object:Gem::Requirement
@@ -82,7 +82,7 @@ dependencies:
82
82
  version: 1.2.7
83
83
  - - "<"
84
84
  - !ruby/object:Gem::Version
85
- version: '1.4'
85
+ version: '2.1'
86
86
  - !ruby/object:Gem::Dependency
87
87
  name: rubyzip
88
88
  requirement: !ruby/object:Gem::Requirement