Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 6 additions & 11 deletions Readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -166,39 +166,34 @@ xalan/xerces libraries used by those gems are popular ones in the Java world.

# Troubleshooting

Since maven is used under the hood it is possible to get more insight
what maven is doing. Show the regular maven output:
Jar dependency resolution uses the bundled Mima resolver. To get more
insight into jar-dependencies progress and warnings, enable verbose output:

```shell
JARS_VERBOSE=true bundle install
JARS_VERBOSE=true gem install some_gem
```


Or, with maven debug enabled
For Ruby-side debug diagnostics, including backtraces for suppressed setup
errors and jar loading decisions, enable debug output:

```shell
JARS_DEBUG=true bundle install
JARS_DEBUG=true gem install some_gem
```

The maven command line which gets printed needs maven-3.9.x and the
ruby DSL extension for maven:
[polyglot-maven
configuration](https://github.com/takari/polyglot-maven#configuration) where `${maven.multiModuleProjectDirectory}` is
your current directory.

# Configuration

<table border='1'>
<tr>
<td>ENV</td><td>java system property</td><td>default</td><td>description</td>
</tr>
<tr>
<td><tt>JARS_DEBUG</tt></td><td>jars.debug</td><td>false</td><td>if set to true it will produce lots of debug out (maven -X switch)</td>
<td><tt>JARS_DEBUG</tt></td><td>jars.debug</td><td>false</td><td>if set to true it will produce Ruby-side debug diagnostics and implies verbose output</td>
</tr>
<tr>
<td><tt>JARS_VERBOSE</tt></td><td>jars.verbose</td><td>false</td><td>if set to true it will produce some extra output</td>
<td><tt>JARS_VERBOSE</tt></td><td>jars.verbose</td><td>false</td><td>if set to true it will produce some extra resolver output</td>
</tr>
<tr>
<td><tt>JARS_HOME</tt></td><td>jars.home</td><td>$HOME/.m2/repository</td><td>filesystem location where to store the jar files and some metadata</td>
Expand Down
91 changes: 51 additions & 40 deletions lib/jar_dependencies.rb
Original file line number Diff line number Diff line change
Expand Up @@ -22,34 +22,34 @@
#

module Jars
unless defined? Jars::SKIP_LOCK
MAVEN_SETTINGS = 'JARS_MAVEN_SETTINGS'
LOCAL_MAVEN_REPO = 'JARS_LOCAL_MAVEN_REPO'
# lock file to use
LOCK = 'JARS_LOCK'
# where the locally stored jars are search for or stored
HOME = 'JARS_HOME'
# skip the gem post install hook
SKIP = 'JARS_SKIP'
# skip Jars.lock mainly to run lock_jars
SKIP_LOCK = 'JARS_SKIP_LOCK'
# do not require any jars if set to false
REQUIRE = 'JARS_REQUIRE'
# @private
NO_REQUIRE = 'JARS_NO_REQUIRE'
# no more warnings on conflict. this still requires jars but will
# not warn. it is needed to load jars from (default) gems which
# do contribute to any dependency manager (maven, gradle, jbundler)
QUIET = 'JARS_QUIET'
# show maven output
VERBOSE = 'JARS_VERBOSE'
# maven debug
DEBUG = 'JARS_DEBUG'
# vendor jars inside gem when installing gem
VENDOR = 'JARS_VENDOR'
# string used when the version is unknown
UNKNOWN = 'unknown'
end
# rubocop:disable Style/RedundantFreeze
MAVEN_SETTINGS = 'JARS_MAVEN_SETTINGS'.freeze
LOCAL_MAVEN_REPO = 'JARS_LOCAL_MAVEN_REPO'.freeze
# lock file to use
LOCK = 'JARS_LOCK'.freeze
# where the locally stored jars are search for or stored
HOME = 'JARS_HOME'.freeze
# skip the gem post install hook
SKIP = 'JARS_SKIP'.freeze
# skip Jars.lock mainly to run lock_jars
SKIP_LOCK = 'JARS_SKIP_LOCK'.freeze
# do not require any jars if set to false
REQUIRE = 'JARS_REQUIRE'.freeze
# @private
NO_REQUIRE = 'JARS_NO_REQUIRE'.freeze
# no more warnings on conflict. this still requires jars but will
# not warn. it is needed to load jars from (default) gems which
# do contribute to any dependency manager (maven, gradle, jbundler)
QUIET = 'JARS_QUIET'.freeze
# show resolver output
VERBOSE = 'JARS_VERBOSE'.freeze
# show jar-dependencies debug output
DEBUG = 'JARS_DEBUG'.freeze
# vendor jars inside gem when installing gem
VENDOR = 'JARS_VENDOR'.freeze
# string used when the version is unknown
UNKNOWN = 'unknown'.freeze
# rubocop:enable Style/RedundantFreeze

autoload :Classpath, 'jars/classpath'
autoload :MavenSettings, 'jars/maven_settings'
Expand All @@ -58,13 +58,22 @@ module Jars
@jars_lock = false
@jars = {}

class JarLoadError < LoadError; end

class << self
def lock_down(debug: false, verbose: false, **kwargs)
def lock_down(debug: nil, verbose: nil, **kwargs)
previous_debug = ENV[DEBUG]
previous_verbose = ENV[VERBOSE]
previous_skip_lock = ENV[SKIP_LOCK]
ENV[DEBUG] = debug.to_s unless debug.nil?
ENV[VERBOSE] = verbose.to_s unless verbose.nil?
ENV[SKIP_LOCK] = 'true'
require 'jars/lock_down' # do this lazy to keep things clean
Jars::LockDown.new(debug, verbose).lock_down(kwargs.delete(:vendor_dir), **kwargs)
ensure
ENV[SKIP_LOCK] = nil
ENV[DEBUG] = previous_debug unless debug.nil?
ENV[VERBOSE] = previous_verbose unless verbose.nil?
ENV[SKIP_LOCK] = previous_skip_lock
end

if defined? JRUBY_VERSION
Expand Down Expand Up @@ -119,7 +128,8 @@ def jarfile
end

def verbose?
to_boolean(VERBOSE)
verbose = to_boolean(VERBOSE)
verbose.nil? ? debug? : (verbose || !!debug?)
end

def debug?
Expand Down Expand Up @@ -266,7 +276,7 @@ def require_jar(group_id, artifact_id, *classifier_version)
end

def warn(msg = nil)
return if (verbose? == nil && quiet?) || (verbose? == false && !debug?)
return if quiet? && !debug?

Kernel.warn(msg || yield)
end
Expand Down Expand Up @@ -324,8 +334,8 @@ def detect_local_repository(settings)
local_repo = nil if local_repo.empty? || !File.exist?(local_repo)
local_repo
rescue => e
Jars.debug(e)
Jars.warn "error reading or parsing local settings from: #{settings}"
Jars.debug(e)
nil
end

Expand All @@ -352,25 +362,26 @@ def do_require(*args)
require jar
end
rescue LoadError => e
raise "\n\n\tyou might need to reinstall the gem which depends on the " \
'missing jar or in case there is Jars.lock then resolve the jars with ' \
"`lock_jars` command\n\n#{e.message} (LoadError)"
Jars.warn "failed to load jar: #{jar} (#{e.message})"
Jars.debug(e)
raise JarLoadError, "failed to load jar: #{jar}; run `lock_jars` or reinstall the gem"
end
end
end

def require_jar(*args, &block)
return nil unless Jars.require?
return unless Jars.require?

result = Jars.require_jar(*args, &block)
if result.is_a? String
args << (yield || Jars::UNKNOWN) if args.size == 2 && block
Jars.warn do
"--- jar coordinate #{args[0..-2].join(':')} already loaded with version #{result} - omit version #{args[-1]}"
"jar conflict: #{args[0..-2].join(':')} already loaded with version #{result}; " \
"skipping requested version #{args[-1]}"
end
Jars.debug { " try to load from #{caller.join("\n\t")}" }
Jars.debug("\n\t#{caller.join("\n\t")}") if Jars.debug?
return false
end
Jars.debug { " register #{args.inspect} - #{result == true}" }
Jars.debug { "jar registration: #{args.inspect}; loaded=#{result == true}" }
result
end
2 changes: 1 addition & 1 deletion lib/jars/gemspec_artifacts.rb
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ def convert(arg, low = nil, high = nil)
elsif arg.include?('<=')
val = arg.sub(/<=\s*/, '')
[low, "#{snapshot_version(val)}]"]
# treat '!' the same way as '>' since maven can not describe such range
# treat '!' the same way as '>' since maven cannot describe such range
elsif /[!>]/.match?(arg)
val = arg.sub(/[!>]\s*/, '')
["(#{snapshot_version(val)}", high]
Expand Down
22 changes: 10 additions & 12 deletions lib/jars/installer.rb
Original file line number Diff line number Diff line change
Expand Up @@ -178,10 +178,11 @@ def jars?
# first look if there are any requirements in the spec
# and then if gem depends on jar-dependencies for runtime.
# only then install the jars declared in the requirements
result = (spec = self.spec) && !spec.requirements.empty? &&
spec = self.spec
result = spec && !spec.requirements.empty? &&
spec.dependencies.detect { |d| d.name == 'jar-dependencies' && d.type == :runtime }
if result && spec.platform.to_s != 'java'
Jars.warn "\njar dependencies found on non-java platform gem - do not install jars\n"
Jars.warn "jar-dependencies found on non-java platform gem; skipping jar installation"
false
else
result
Expand All @@ -191,21 +192,18 @@ def jars?
private

def do_install(vendor_dir, write_require_file)
if !spec.require_paths.include?(vendor_dir) && vendor_dir
raise "vendor dir #{vendor_dir} not in require_paths of gemspec #{spec.require_paths}"
require_paths = spec.require_paths
if vendor_dir && !require_paths.include?(vendor_dir)
raise "vendor dir #{vendor_dir} not in require_paths of gemspec #{require_paths}"
end

target_dir = File.join(@mvn.basedir, vendor_dir || spec.require_path)
jars_file = File.join(target_dir, "#{spec.name}_jars.rb")

# write out new jars_file it write_require_file is true or
# check timestamps:
# do not generate file if specfile is older then the generated file
if !write_require_file &&
File.exist?(jars_file) &&
File.mtime(@mvn.specfile) < File.mtime(jars_file)
# leave jars_file as is
jars_file = nil
# write out new jars_file if write_require_file is true or check timestamps:
# do not generate file if specfile is older than the generated file
if !write_require_file && File.exist?(jars_file) && File.mtime(@mvn.specfile) < File.mtime(jars_file)
jars_file = nil # leave jars_file as is
end
deps = install_dependencies
self.class.write_require_jars(deps, jars_file)
Expand Down
9 changes: 3 additions & 6 deletions lib/jars/lock_down.rb
Original file line number Diff line number Diff line change
Expand Up @@ -59,14 +59,11 @@ def attach_jar_coordinates_from_bundler_dependencies(artifacts, done)
end
end
rescue LoadError => e
if Jars.verbose?
warn e.message
warn 'no bundler found - ignore Gemfile if exists'
end
Jars.warn "bundler unavailable (#{e.message}); skipping dependency discovery" if Jars.verbose?
rescue Bundler::GemfileNotFound
# do nothing then as we have bundler but no Gemfile
# bundler is available, but there is no Gemfile to inspect
rescue Bundler::GemNotFound
warn "can not setup bundler with #{Bundler.default_lockfile}"
Jars.warn "cannot set up bundler with #{Bundler.default_lockfile}"
raise
ensure
$LOAD_PATH.replace(load_path)
Expand Down
18 changes: 5 additions & 13 deletions lib/jars/maven_exec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -13,20 +13,18 @@ def find_spec(allow_no_file)
when 1
specs.first
else
raise 'more then one gemspec found. please specify a specfile' unless allow_no_file
raise 'more than one gemspec found; please specify a specfile' unless allow_no_file
end
end
private :find_spec

attr_reader :basedir, :spec, :specfile

def initialize(spec = nil)
@options = {}
setup(spec)
rescue StandardError, LoadError => e
# If spec load fails, skip looking for jar-dependencies
warn "jar-dependencies: #{e}"
warn e.backtrace.join("\n") if Jars.verbose?
Jars.warn "unable to load gemspec (#{e.message}); skipping jar dependency discovery"
Jars.debug(e)
end

def setup(spec = nil, allow_no_file: false)
Expand All @@ -45,25 +43,19 @@ def setup(spec = nil, allow_no_file: false)
@specfile = spec.loaded_from
else
# this happens with bundle and local gems
# there the spec_file is "not installed" but inside
# the gem_dir directory
# there spec_file is "not installed" but is inside the gem_dir directory
Dir.chdir(spec.gem_dir) do
setup(nil, allow_no_file: true)
end
end
when nil
# ignore
else
Jars.debug('spec must be either String or Gem::Specification. ' \
'File an issue on github if you need it.')
Jars.debug "unsupported spec argument #{spec.class}; expected String or Gem::Specification"
end
@spec = spec
end

def ruby_maven_install_options=(options)
@options = options
end

def resolve_dependencies_list(file)
require 'jars/mima'

Expand Down
Loading
Loading