jar-dependencies-0.5.5/0000755000004100000410000000000014770336505014763 5ustar www-datawww-datajar-dependencies-0.5.5/exe/0000755000004100000410000000000014770336505015544 5ustar www-datawww-datajar-dependencies-0.5.5/exe/lock_jars0000755000004100000410000000303514770336505017442 0ustar www-datawww-data#!/usr/bin/env ruby # frozen_string_literal: true require 'jar_dependencies' require 'optparse' options = {} optparse = OptionParser.new do |opts| opts.banner = "Usage: #{File.basename(__FILE__)} [options]" opts.separator '' opts.separator 'Options:' opts.separator '' opts.on('-v', '--verbose', 'Output more information') do |t| options[:verbose] = t end opts.on('-d', '--debug', 'Output debug information') do |t| options[:debug] = t end opts.on('-f', '--force', 'Force creation of Jars.lock') do |t| options[:force] = t end opts.on('-t', '--tree', 'Show dependency tree') do |t| options[:tree] = t end opts.on('-u', '--update JAR_COORDINATE', 'Resolves given dependency and use latest version. ' \ 'JAR_COORDINATE is either artifact_id or group_id:artifact_id') do |u| options[:update] = u end opts.on('--vendor-dir DIRECTORY', 'Vendor directory where to copy the installed jars.' \ 'add this directory to $LOAD_PATH or set JARS_HOME respectively.') do |dir| options[:vendor_dir] = dir end opts.on('-h', '--help', 'Display this screen') do puts opts exit end opts.separator '' opts.separator 'THIS IS A EXPERIMETAL FEATURE !!!' opts.separator '' opts.separator '* load jars "Jars.lock" from current working directory: `Jars.require_jars_lock!`' opts.separator '* classpath features: see `Jars::Classpath' end optparse.parse! Jars.lock_down(debug: options.delete(:debug), verbose: options.delete(:verbose), **options) jar-dependencies-0.5.5/lib/0000755000004100000410000000000014770336505015531 5ustar www-datawww-datajar-dependencies-0.5.5/lib/rubygems_plugin.rb0000644000004100000410000000221014770336505021264 0ustar www-datawww-data# frozen_string_literal: true # # Copyright (C) 2014 Christian Meier # # Permission is hereby granted, free of charge, to any person obtaining a copy of # this software and associated documentation files (the "Software"), to deal in # the Software without restriction, including without limitation the rights to # use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of # the Software, and to permit persons to whom the Software is furnished to do so, # subject to the following conditions: # # The above copyright notice and this permission notice shall be included in all # copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS # FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR # COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER # IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN # CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # require 'jars/post_install_hook' jar-dependencies-0.5.5/lib/jar_dependencies.rb0000644000004100000410000002540414770336505021345 0ustar www-datawww-data# frozen_string_literal: true # # Copyright (C) 2014 Christian Meier # # Permission is hereby granted, free of charge, to any person obtaining a copy of # this software and associated documentation files (the "Software"), to deal in # the Software without restriction, including without limitation the rights to # use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of # the Software, and to permit persons to whom the Software is furnished to do so, # subject to the following conditions: # # The above copyright notice and this permission notice shall be included in all # copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS # FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR # COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER # IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN # CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # 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 autoload :MavenSettings, 'jars/maven_settings' autoload :Classpath, 'jars/classpath' @jars_lock = false @jars = {} class << self def lock_down(debug: false, verbose: false, **kwargs) 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 end if defined? JRUBY_VERSION def to_prop(key) key = key.tr('_', '.') ENV_JAVA[(key.downcase! key)] || ENV[(key.tr!('.', '_') key.upcase! key)] end else def to_prop(key) ENV[key.tr('.', '_').upcase] end end def to_boolean(key) return nil if (prop = to_prop(key)).nil? prop.empty? || prop.eql?('true') end def skip? to_boolean(SKIP) end def require? if @require.nil? if (require = to_boolean(REQUIRE)).nil? no_require = to_boolean(NO_REQUIRE) @require = no_require.nil? ? true : !no_require else @require = require end end @require end attr_writer :require def quiet? @quiet = to_boolean(QUIET) if @quiet.nil? @quiet end def no_more_warnings @quiet = true end def jarfile ENV['JARFILE'] || ENV_JAVA['jarfile'] || ENV['JBUNDLER_JARFILE'] || ENV_JAVA['jbundler.jarfile'] || 'Jarfile' end def verbose? to_boolean(VERBOSE) end def debug? to_boolean(DEBUG) end def vendor? to_boolean(VENDOR) end def freeze_loading self.require = false end def skip_lock? to_prop(SKIP_LOCK) || false end def lock @lock ||= to_prop(LOCK) || 'Jars.lock' end def jars_lock_from_class_loader return unless defined?(JRUBY_VERSION) if JRuby::Util.respond_to?(:class_loader_resources) JRuby::Util.class_loader_resources('Jars.lock') else require 'jruby' JRuby.runtime.jruby_class_loader.get_resources('Jars.lock').collect(&:to_s) end end def lock_path(basedir = nil) return lock if File.exist?(lock) basedir ||= '.' ['.', 'jars', 'vendor/jars'].each do |dir| file = File.join(basedir, dir, lock) return file if File.exist?(file) end nil end def reset instance_variables.each do |var| next if var == :@jars_lock instance_variable_set(var, nil) end Jars::MavenSettings.reset @jars = {} end def maven_local_settings Jars::MavenSettings.local_settings end def maven_user_settings Jars::MavenSettings.user_settings end def maven_settings Jars::MavenSettings.settings end def maven_global_settings Jars::MavenSettings.global_settings end def local_maven_repo @local_maven_repo ||= absolute(to_prop(LOCAL_MAVEN_REPO)) || detect_local_repository(maven_local_settings) || detect_local_repository(maven_user_settings) || detect_local_repository(maven_global_settings) || File.join(user_home, '.m2', 'repository') end def home @home ||= absolute(to_prop(HOME)) || local_maven_repo end def require_jars_lock!(scope = :runtime) urls = jars_lock_from_class_loader if to_prop(LOCK).nil? if urls && !urls.empty? @jars_lock = true done = [] while done != urls urls.each do |url| next if done.member?(url) Jars.debug { "--- load jars from uri #{url}" } classpath = Jars::Classpath.new(nil, "uri:#{url}") classpath.require(scope) done << url end end no_more_warnings elsif (jars_lock = Jars.lock_path) Jars.debug { "--- load jars from #{jars_lock}" } @jars_lock = jars_lock classpath = Jars::Classpath.new(nil, jars_lock) classpath.require(scope) no_more_warnings end Jars.debug do loaded = @jars.collect { |k, v| "#{k}:#{v}" } "--- loaded jars ---\n\t#{loaded.join("\n\t")}" end end def setup(options = nil) case options when Symbol require_jars_lock!(options) when Hash @home = options[:jars_home] @lock = options[:jars_lock] require_jars_lock!(options[:scope] || :runtime) else require_jars_lock! end end def require_jars_lock return if @jars_lock require_jars_lock! @jars_lock ||= true # rubocop:disable Naming/MemoizedInstanceVariableName end def mark_as_required(group_id, artifact_id, *classifier_version) require_jar_with_block(group_id, artifact_id, *classifier_version) do # ignore end end def require_jar(group_id, artifact_id, *classifier_version) require_jars_lock unless skip_lock? if classifier_version.empty? && block_given? classifier_version = [yield].compact return mark_as_required(group_id, artifact_id, UNKNOWN) || false if classifier_version.empty? end require_jar_with_block(group_id, artifact_id, *classifier_version) do |gid, aid, version, classifier| do_require(gid, aid, version, classifier) end end def warn(msg = nil) return if (verbose? == nil && quiet?) || (verbose? == false && !debug?) Kernel.warn(msg || yield) end def debug(msg = nil) return unless debug? msg = "#{msg.inspect}\n\t#{(msg.backtrace || []).join("\n\t")}" if msg.is_a?(Exception) Kernel.warn(msg || yield) end def absolute(file) File.expand_path(file) if file end def user_home ENV['HOME'] || begin user_home = Dir.home if Dir.respond_to?(:home) user_home = ENV_JAVA['user.home'] if !user_home && Object.const_defined?(:ENV_JAVA) user_home end end private def require_jar_with_block(group_id, artifact_id, *classifier_version) version = classifier_version[-1] classifier = classifier_version[-2] coordinate = +"#{group_id}:#{artifact_id}" coordinate << ":#{classifier}" if classifier if @jars.key? coordinate if @jars[coordinate] == version false else @jars[coordinate] # version of already registered jar end else yield group_id, artifact_id, version, classifier @jars[coordinate] = version true end end def detect_local_repository(settings) return nil unless settings doc = File.read(settings) # TODO: filter out xml comments local_repo = doc.sub(%r{.*}m, '').sub(/.*/m, '') # replace maven like system properties embedded into the string local_repo.gsub!(/\$\{[a-zA-Z.]+\}/) do |a| ENV_JAVA[a[2..-2]] || a end 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}" nil end def to_jar(group_id, artifact_id, version, classifier = nil) file = +"#{group_id.tr('.', '/')}/#{artifact_id}/#{version}/#{artifact_id}-#{version}" file << "-#{classifier}" if classifier file << '.jar' file end def do_require(*args) jar = to_jar(*args) # use jar from PWD/vendor/jars if exists if File.exist?(vendor = File.join(Dir.pwd, 'vendor', 'jars', jar)) require vendor # use jar from PWD/jars if exists elsif File.exist?(local = File.join(Dir.pwd, 'jars', jar)) require local # use jar from local repository if exists elsif File.exist?(file = File.join(home, jar)) require file else # otherwise try to find it on the load path 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)" end end end def require_jar(*args, &block) return nil 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]}" end Jars.debug { " try to load from #{caller.join("\n\t")}" } return false end Jars.debug { " register #{args.inspect} - #{result == true}" } result end jar-dependencies-0.5.5/lib/jar-dependencies.rb0000644000004100000410000000220314770336505021253 0ustar www-datawww-data# frozen_string_literal: true # # Copyright (C) 2014 Christian Meier # # Permission is hereby granted, free of charge, to any person obtaining a copy of # this software and associated documentation files (the "Software"), to deal in # the Software without restriction, including without limitation the rights to # use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of # the Software, and to permit persons to whom the Software is furnished to do so, # subject to the following conditions: # # The above copyright notice and this permission notice shall be included in all # copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS # FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR # COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER # IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN # CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # require 'jar_dependencies' jar-dependencies-0.5.5/lib/jars/0000755000004100000410000000000014770336505016470 5ustar www-datawww-datajar-dependencies-0.5.5/lib/jars/lock_down_pom.rb0000644000004100000410000000151614770336505021652 0ustar www-datawww-data# frozen_string_literal: true # this file is maven DSL and used by maven via jars/lock_down.rb basedir(ENV_JAVA['jars.basedir']) def eval_file(file) file = File.join(__dir__, file) eval(File.read(file), nil, file) # rubocop:disable Security/Eval end eval_file('attach_jars_pom.rb') jfile = ENV_JAVA['jars.jarfile'] jarfile(jfile) if jfile # need to fix the version of this plugin for gem:jars_lock goal jruby_plugin :gem, ENV_JAVA['jruby.plugins.version'] # if you use bundler we collect all root jar dependencies # from each gemspec file. otherwise we need to resolve # the gemspec artifact in the maven way unless ENV_JAVA['jars.bundler'] begin gemspec rescue nil end end properties('project.build.sourceEncoding' => 'utf-8') plugin :dependency, ENV_JAVA['dependency.plugin.version'] eval_file('output_jars_pom.rb') jar-dependencies-0.5.5/lib/jars/lock_down.rb0000644000004100000410000000576014770336505021004 0ustar www-datawww-data# frozen_string_literal: true require 'fileutils' require 'jar_dependencies' require 'jars/version' require 'jars/maven_factory' require 'jars/gemspec_artifacts' module Jars class LockDown attr_reader :debug, :verbose def initialize(debug, verbose) @debug = debug @verbose = verbose end def maven_new factory = MavenFactory.new({}, @debug, @verbose) pom = File.expand_path('lock_down_pom.rb', __dir__) m = factory.maven_new(pom) m['jruby.plugins.version'] = Jars::JRUBY_PLUGINS_VERSION m['dependency.plugin.version'] = Jars::DEPENDENCY_PLUGIN_VERSION m['jars.basedir'] = File.expand_path(basedir) jarfile = File.expand_path(Jars.jarfile) m['jars.jarfile'] = jarfile if File.exist?(jarfile) attach_jar_coordinates_from_bundler_dependencies(m) m end private :maven_new def maven @maven ||= maven_new end def basedir File.expand_path('.') end def attach_jar_coordinates_from_bundler_dependencies(maven) load_path = $LOAD_PATH.dup require 'bundler' # TODO: make this group a commandline option Bundler.setup('default') maven.property('jars.bundler', true) cwd = File.expand_path('.') Gem.loaded_specs.each do |_name, spec| # if gemspec is local then include all dependencies maven.attach_jars(spec, all_dependencies: cwd == spec.full_gem_path) end rescue LoadError => e if Jars.verbose? warn e.message warn 'no bundler found - ignore Gemfile if exists' end rescue Bundler::GemfileNotFound # do nothing then as we have bundler but no Gemfile rescue Bundler::GemNotFound warn "can not setup bundler with #{Bundler.default_lockfile}" raise ensure $LOAD_PATH.replace(load_path) end def lock_down(vendor_dir = nil, force: false, update: false, tree: nil) out = File.expand_path('.jars.output') tree_provided = tree tree ||= File.expand_path('.jars.tree') maven.property('jars.outputFile', out) maven.property('maven.repo.local', Jars.local_maven_repo) maven.property('jars.home', File.expand_path(vendor_dir)) if vendor_dir maven.property('jars.lock', File.expand_path(Jars.lock)) maven.property('jars.force', force) maven.property('jars.update', update) if update # tell not to use Jars.lock as part of POM when running mvn maven.property('jars.skip.lock', true) args = ['gem:jars-lock'] args += ['dependency:tree', '-P -gemfile.lock', "-DoutputFile=#{tree}"] if tree_provided puts puts '-- jar root dependencies --' puts status = maven.exec(*args) exit 1 unless status if File.exist?(tree) puts puts '-- jar dependency tree --' puts puts File.read(tree) puts end puts puts File.read(out).gsub("#{File.dirname(out)}/", '') puts ensure FileUtils.rm_f out FileUtils.rm_f tree end end end jar-dependencies-0.5.5/lib/jars/settings.xml0000644000004100000410000000103714770336505021053 0ustar www-datawww-data __HTTP_ACTIVE__ http __HTTP_SERVER__ __HTTP_PORT__ __HTTPS_ACTIVE__ https __HTTPS_SERVER__ __HTTPS_PORT__ jar-dependencies-0.5.5/lib/jars/post_install_hook.rb0000644000004100000410000000272014770336505022551 0ustar www-datawww-data# frozen_string_literal: true # # Copyright (C) 2014 Christian Meier # # Permission is hereby granted, free of charge, to any person obtaining a copy of # this software and associated documentation files (the "Software"), to deal in # the Software without restriction, including without limitation the rights to # use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of # the Software, and to permit persons to whom the Software is furnished to do so, # subject to the following conditions: # # The above copyright notice and this permission notice shall be included in all # copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS # FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR # COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER # IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN # CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # if defined?(JRUBY_VERSION) && Gem.post_install_hooks.empty? Gem.post_install do |gem_installer| if ENV['JARS_SKIP'] != 'true' && ENV_JAVA['jars.skip'] != 'true' require 'jars/installer' jars = Jars::Installer.new(gem_installer.spec) jars.ruby_maven_install_options = gem_installer.options || {} jars.vendor_jars end end end jar-dependencies-0.5.5/lib/jars/gemspec_artifacts.rb0000644000004100000410000001325714770336505022510 0ustar www-datawww-data# frozen_string_literal: true module Jars class MavenVersion < String class << self def new(*args) if args.empty? || (args.size == 1 && args[0].nil?) nil else low, high = convert(args[0]) low, high = convert(args[1], low, high) if /[=~><]/.match?(args[1]) if low == high low else super "#{low || '[0'},#{high || ')'}" end end end private def convert(arg, low = nil, high = nil) if arg.include?('~>') val = arg.sub(/~>\s*/, '') last = val.include?('.') ? val.sub(/\.[0-9]*[a-z]+.*$/, '').sub(/\.[^.]+$/, '.99999') : '99999' ["[#{snapshot_version(val)}", "#{snapshot_version(last)}]"] elsif arg.include?('>=') val = arg.sub(/>=\s*/, '') ["[#{snapshot_version(val)}", (nil || high)] elsif arg.include?('<=') val = arg.sub(/<=\s*/, '') [(nil || low), "#{snapshot_version(val)}]"] # treat '!' the same way as '>' since maven can not describe such range elsif /[!>]/.match?(arg) val = arg.sub(/[!>]\s*/, '') ["(#{snapshot_version(val)}", (nil || high)] elsif arg.include?('<') val = arg.sub(/<\s*/, '') [(nil || low), "#{snapshot_version(val)})"] elsif arg.include?('=') val = arg.sub(/=\s*/, '') # for prereleased version pick the maven version (no version range) if /[a-z]|[A-Z]/.match?(val) [val, val] else ["[#{val}", "#{val}.0.0.0.0.1)"] end else # no conversion here, i.e. assume maven version [arg, arg] end end def snapshot_version(val) if val.match(/[a-z]|[A-Z]/) && !val.match(/-SNAPSHOT|[${}]/) "#{val}-SNAPSHOT" else val end end end end class GemspecArtifacts class Exclusion attr_reader :group_id, :artifact_id def initialize(line) @group_id, @artifact_id = line.gsub(/['"]/, '').strip.split(':') @artifact_id.strip! end def to_s "#{@group_id}:#{@artifact_id}" end end class Exclusions < Array def to_s "[#{join(', ')}]" end def initialize(line) super() line.gsub(/'"|^\s*\[|\]\s*$/, '').split(/,\s*/).each do |exclusion| self << Exclusion.new(exclusion) end freeze end end class Artifact attr_reader :type, :group_id, :artifact_id, :classifier, :version, :scope, :exclusions ALLOWED_TYPES = %w[jar pom].freeze def initialize(options, *args) @type, @group_id, @artifact_id, @classifier, @version, @exclusions = *args options.each do |k, v| instance_variable_set(:"@#{k}", v) end end def self.new(line) line = line.strip index = line.index(/\s/) return nil if index.nil? type = line[0..index].strip return nil unless ALLOWED_TYPES.member?(type) line = line[index..] line.gsub!(/['"]/, '') line.strip! options = {} line.sub!(/,\s*:exclusions\s*(:|=>)\s*(\[[^\]]+\])/) do options[:exclusions] = Exclusions.new(Regexp.last_match(2).strip) '' end line.sub!(/,\s*:([a-z]+)\s*(:|=>)\s*(:?[a-zA-Z0-9_]+)/) do options[Regexp.last_match(1).to_sym] = Regexp.last_match(3).sub(/^:/, '') '' end exclusions = nil line.sub!(/[,:]\s*\[(.+:.+,?\s*)+\]$/) do |a| exclusions = Exclusions.new(a[1..].strip) '' end line.strip! line.gsub!(/,\s*/, ':') if /[\[()\]]/.match?(line) index = line.index(/[\[(].+$/) version = line[index..].sub(/:/, ', ') line = line[0..index - 1].strip.sub(/:$/, '') else index = line.index(/:[^:]+$/) version = line[index + 1..] line = line[0..index - 1].strip end case line.count(':') when 2 group_id, artifact_id, classifier = line.split(':') when 1 group_id, artifact_id = line.split(':') classifier = nil else warn line return nil end super(options, type, group_id, artifact_id, classifier, version, exclusions) end def to_s args = [@group_id, @artifact_id] args << @classifier if @classifier args << @version args << @exclusions.to_s if @exclusions "#{@type} #{group_id}:#{args[1..].join(', ')}" end def to_gacv args = [@group_id, @artifact_id] args << @classifier if @classifier args << @version args.join(':') end def to_coord_no_classifier args = [@group_id, @artifact_id] args << @type args << MavenVersion.new(@version) args.join(':') end def to_coord args = [@group_id, @artifact_id] args << @classifier if @classifier args << @type args << MavenVersion.new(@version) args.join(':') end def key args = [@group_id, @artifact_id] args << @classifier if @classifier args.join(':') end end attr_reader :artifacts def initialize(spec) @artifacts = [] spec.requirements.each do |req| req.split("\n").each do |line| if (a = Artifact.new(line)) @artifacts << a end end end @artifacts.freeze end def [](index) @artifacts[index] end def each(&block) @artifacts.each(&block) end def size @artifacts.size end end end jar-dependencies-0.5.5/lib/jars/classpath.rb0000644000004100000410000000374714770336505021012 0ustar www-datawww-data# frozen_string_literal: true require 'jars/maven_exec' require 'jars/lock' require 'fileutils' module Jars class Classpath # convenient method def self.require(scope = nil) new.require(scope) end # convenient method def self.classpath(scope = nil) new.classpath(scope) end # convenient method def self.classpath_string(scope = nil) new.classpath_string(scope) end def initialize(spec = nil, deps = nil) @spec = spec @deps = deps end def mvn @mvn ||= MavenExec.new(@spec) end def workdir(dirname) dir = File.join(mvn.basedir, dirname) dir if File.directory?(dir) end def dependencies_list if @deps.nil? deps = Jars.lock_path(mvn.basedir) @deps = deps if deps && File.exist?(deps) end @deps || resolve_dependencies end private :dependencies_list DEPENDENCY_LIST = 'dependencies.list' def resolve_dependencies basedir = workdir('pkg') || workdir('target') || workdir('') deps = File.join(basedir, DEPENDENCY_LIST) mvn.resolve_dependencies_list(deps) deps end private :resolve_dependencies def require(scope = nil) process(scope) do |jar| if jar.scope == :system Kernel.require jar.path else require_jar(*jar.gacv) end end return unless scope.nil? || scope == :runtime process(:provided) do |jar| Jars.mark_as_required(*jar.gacv) end end def classpath(scope = nil) classpath = [] process(scope) do |jar| classpath << jar.file end classpath end def process(scope, &block) deps = dependencies_list Lock.new(deps).process(scope, &block) ensure # just delete the temporary file if it exists FileUtils.rm_f(DEPENDENCY_LIST) end private :process def classpath_string(scope = nil) classpath(scope).join(File::PATH_SEPARATOR) end end end jar-dependencies-0.5.5/lib/jars/maven_factory.rb0000644000004100000410000001000514770336505021646 0ustar www-datawww-data# frozen_string_literal: true require 'jar_dependencies' require 'jars/gemspec_artifacts' module Jars class MavenFactory module AttachJars def attach_jars(spec, all_dependencies: false) @index ||= 0 @done ||= [] deps = GemspecArtifacts.new(spec) deps.artifacts.each do |a| # for this gemspec we want to include all artifacts but # for all others we want to exclude provided and test artifacts next unless !@done.include?(a.key) && (all_dependencies || ((a.scope != 'provided') && (a.scope != 'test'))) # ruby dsl is not working reliably for classifier self["jars.#{@index}"] = a.to_coord_no_classifier if a.exclusions jndex = 0 a.exclusions.each do |ex| self["jars.#{@index}.exclusions.#{jndex}"] = ex.to_s jndex += 1 end end self["jars.#{@index}.scope"] = a.scope if a.scope self["jars.#{@index}.classifier"] = a.classifier if a.classifier @index += 1 @done << a.key end end end attr_reader :debug, :verbose def initialize(options = nil, debug = Jars.debug?, verbose = Jars.verbose?) @options = (options || {}).dup @options.delete(:ignore_dependencies) @debug = debug @verbose = verbose @installed_maven = false end def maven_new(pom) lazy_load_maven maven = setup(Maven::Ruby::Maven.new) maven.extend AttachJars # TODO: copy pom to tmp dir in case it is not a real file maven.options['-f'] = pom maven end private def setup(maven) maven.verbose = @verbose maven.options['-X'] = nil if @debug if @verbose maven.options['-e'] = nil elsif !@debug maven.options['--quiet'] = nil end maven['verbose'] = (@debug || @verbose) == true maven.options['-s'] = Jars::MavenSettings.effective_settings if Jars.maven_settings maven['maven.repo.local'] = java.io.File.new(Jars.local_maven_repo).absolute_path.to_s maven end def lazy_load_maven add_gem_to_load_path('ruby-maven') add_gem_to_load_path('ruby-maven-libs') if @installed_maven puts puts 'using maven for the first time results in maven' puts 'downloading all its default plugin and can take time.' puts 'as those plugins get cached on disk and further execution' puts 'of maven is much faster then the first time.' puts end require 'maven/ruby/maven' end def find_spec_via_rubygems(name, req) require 'rubygems/dependency' dep = Gem::Dependency.new(name, req) dep.matching_specs(true).last end def add_gem_to_load_path(name) # if the gem is already activated => good return if Gem.loaded_specs[name] # just install gem if needed and add it to the load_path # and leave activated gems as they are req = requirement(name) unless (spec = find_spec_via_rubygems(name, req)) spec = install_gem(name, req) end raise "failed to resolve gem '#{name}' if you're using Bundler add it as a dependency" unless spec path = File.join(spec.full_gem_path, spec.require_path) $LOAD_PATH << path unless $LOAD_PATH.include?(path) end def requirement(name) jars = Gem.loaded_specs['jar-dependencies'] dep = jars&.dependencies&.detect { |d| d.name == name } dep.nil? ? Gem::Requirement.create('>0') : dep.requirement end def install_gem(name, req) @installed_maven = true puts "Installing gem '#{name}' . . ." require 'rubygems/dependency_installer' inst = Gem::DependencyInstaller.new(@options ||= {}) inst.install(name, req).first rescue => e if Jars.verbose? warn e.inspect warn e.backtrace.join("\n") end raise "there was an error installing '#{name} (#{req})' " \ "#{@options[:domain]}. please install it manually: #{e.inspect}" end end end jar-dependencies-0.5.5/lib/jars/attach_jars_pom.rb0000644000004100000410000000122014770336505022146 0ustar www-datawww-data# frozen_string_literal: true # this file is maven DSL 10_000.times do |i| coord = ENV_JAVA["jars.#{i}"] break unless coord artifact = Maven::Tools::Artifact.from_coordinate(coord) exclusions = [] 10_000.times do |j| exclusion = ENV_JAVA["jars.#{i}.exclusions.#{j}"] break unless exclusion exclusions << exclusion end scope = ENV_JAVA["jars.#{i}.scope"] artifact.scope = scope if scope classifier = ENV_JAVA["jars.#{i}.classifier"] artifact.classifier = classifier if classifier # declare the artifact inside the POM dependency_artifact(artifact) do exclusions.each do |ex| exclusion ex end end end jar-dependencies-0.5.5/lib/jars/installer.rb0000644000004100000410000001432114770336505021013 0ustar www-datawww-data# frozen_string_literal: true require 'jar_dependencies' require 'jars/maven_exec' module Jars class Installer class Dependency attr_reader :path, :file, :gav, :scope, :type, :coord def self.new(line) super if /:jar:|:pom:/.match?(line) end def setup_type(line) if line.index(':pom:') @type = :pom elsif line.index(':jar:') @type = :jar end end private :setup_type def setup_scope(line) @scope = case line when /:provided:/ :provided when /:test:/ :test else :runtime end end private :setup_scope REG = /:jar:|:pom:|:test:|:compile:|:runtime:|:provided:|:system:/.freeze EMPTY = '' def initialize(line) # remove ANSI escape sequences and module section (https://issues.apache.org/jira/browse/MDEP-974) line = line.gsub(/\e\[\d*m/, '') line = line.gsub(/ -- module.*/, '') setup_type(line) line.strip! @coord = line.sub(/:[^:]+:([A-Z]:\\)?[^:]+$/, EMPTY) first, second = @coord.split(/:#{type}:/) group_id, artifact_id = first.split(':') parts = group_id.split('.') parts << artifact_id parts << second.split(':')[-1] @file = line.slice(@coord.length, line.length).sub(REG, EMPTY).strip last = @file.reverse.index(%r{\\|/}) parts << line[-last..] @path = File.join(parts).strip setup_scope(line) @system = !line.index(':system:').nil? @gav = @coord.sub(REG, ':') end def system? @system end end def self.install_jars(write_require_file: false) new.install_jars(write_require_file: write_require_file) end def self.load_from_maven(file) result = [] File.read(file).each_line do |line| dep = Dependency.new(line) result << dep if dep && dep.scope == :runtime end result end def self.vendor_file(dir, dep) return unless !dep.system? && dep.type == :jar && dep.scope == :runtime vendored = File.join(dir, dep.path) FileUtils.mkdir_p(File.dirname(vendored)) FileUtils.cp(dep.file, vendored) end def self.print_require_jar(file, dep, fallback: false) return if dep.type != :jar || dep.scope != :runtime if dep.system? file&.puts("require '#{dep.file}'") elsif dep.scope == :runtime if fallback file&.puts(" require '#{dep.path}'") else file&.puts(" require_jar '#{dep.gav.gsub(':', "', '")}'") end end end COMMENT = '# this is a generated file, to avoid over-writing it just delete this comment' def self.needs_to_write?(require_filename) require_filename && (!File.exist?(require_filename) || File.read(require_filename).match(COMMENT)) end def self.write_require_jars(deps, require_filename) return unless needs_to_write?(require_filename) FileUtils.mkdir_p(File.dirname(require_filename)) File.open(require_filename, 'w') do |f| f.puts COMMENT f.puts 'begin' f.puts " require 'jar_dependencies'" f.puts 'rescue LoadError' deps.each do |dep| # do not use require_jar method print_require_jar(f, dep, fallback: true) end f.puts 'end' f.puts f.puts 'if defined? Jars' deps.each do |dep| print_require_jar(f, dep) end f.puts 'end' end end def self.vendor_jars(deps, dir) deps.each do |dep| vendor_file(dir, dep) end end def initialize(spec = nil) @mvn = MavenExec.new(spec) end def spec @mvn.spec end def vendor_jars(vendor_dir = nil, write_require_file: true) return unless jars? if Jars.to_prop(Jars::VENDOR) == 'false' vendor_dir = nil else vendor_dir ||= spec.require_path end do_install(vendor_dir, write_require_file) end def self.vendor_jars!(vendor_dir = nil) new.vendor_jars!(vendor_dir) end def vendor_jars!(vendor_dir = nil, write_require_file: true) vendor_dir ||= spec.require_path do_install(vendor_dir, write_require_file) end def install_jars(write_require_file: true) return unless jars? do_install(nil, write_require_file) end def ruby_maven_install_options=(options) @mvn.ruby_maven_install_options = options end 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.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" false else result end end 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}" 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 end deps = install_dependencies self.class.write_require_jars(deps, jars_file) self.class.vendor_jars(deps, target_dir) if vendor_dir end def install_dependencies deps = File.join(@mvn.basedir, 'deps.lst') puts " jar dependencies for #{spec.spec_name} . . ." unless Jars.quiet? @mvn.resolve_dependencies_list(deps) self.class.load_from_maven(deps) ensure FileUtils.rm_f(deps) if deps end end end jar-dependencies-0.5.5/lib/jars/gemspec_pom.rb0000644000004100000410000000044114770336505021312 0ustar www-datawww-data# frozen_string_literal: true # this file is maven DSL and used by maven via jars/maven_exec.rb def eval_file(file) file = File.join(__dir__, file) eval(File.read(file), nil, file) # rubocop:disable Security/Eval end eval_file('attach_jars_pom.rb') eval_file('output_jars_pom.rb') jar-dependencies-0.5.5/lib/jars/maven_exec.rb0000644000004100000410000000474714770336505021143 0ustar www-datawww-data# frozen_string_literal: true require 'jar_dependencies' require 'jars/maven_factory' module Jars class MavenExec def find_spec(allow_no_file) specs = Dir['*.gemspec'] case specs.size when 0 raise 'no gemspec found' unless allow_no_file when 1 specs.first else raise 'more then 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? end def setup(spec = nil, allow_no_file: false) spec ||= find_spec(allow_no_file) case spec when String @specfile = File.expand_path(spec) @basedir = File.dirname(@specfile) Dir.chdir(@basedir) do spec = eval(File.read(@specfile), TOPLEVEL_BINDING, @specfile) # rubocop:disable Security/Eval end when Gem::Specification if File.exist?(spec.loaded_from) @basedir = spec.gem_dir @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 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.') end @spec = spec end def ruby_maven_install_options=(options) @options = options end def resolve_dependencies_list(file) factory = MavenFactory.new(@options) maven = factory.maven_new(File.expand_path('gemspec_pom.rb', __dir__)) is_local_file = File.expand_path(File.dirname(@specfile)) == File.expand_path(Dir.pwd) maven.attach_jars(@spec, all_dependencies: is_local_file) maven['jars.specfile'] = @specfile.to_s maven['outputAbsoluteArtifactFilename'] = 'true' maven['includeTypes'] = 'jar' maven['outputScope'] = 'true' maven['useRepositoryLayout'] = 'true' maven['outputDirectory'] = Jars.home.to_s maven['outputFile'] = file.to_s maven.exec('dependency:copy-dependencies', 'dependency:list') end end end jar-dependencies-0.5.5/lib/jars/output_jars_pom.rb0000644000004100000410000000066714770336505022260 0ustar www-datawww-data# frozen_string_literal: true # this file is maven DSL if ENV_JAVA['jars.quiet'] != 'true' model.dependencies.each do |d| puts " #{d.group_id}:#{d.artifact_id}" \ "#{d.classifier ? ":#{d.classifier}" : ''}" \ ":#{d.version}:#{d.scope || 'compile'}" next if d.exclusions.empty? puts " exclusions: #{d.exclusions.collect do |e| "#{e.group_id}:#{e.artifact_id}" end.join}" end end jar-dependencies-0.5.5/lib/jars/version.rb0000644000004100000410000000021114770336505020474 0ustar www-datawww-data# frozen_string_literal: true module Jars VERSION = '0.5.5' JRUBY_PLUGINS_VERSION = '3.0.2' DEPENDENCY_PLUGIN_VERSION = '2.8' end jar-dependencies-0.5.5/lib/jars/setup.rb0000644000004100000410000000035314770336505020156 0ustar www-datawww-data# frozen_string_literal: true # to do as bundler does and allow to load Jars.lock via # require 'jars/setup'. can be useful via commandline -rjars/setup # or tell bundler autorequire to load it require 'jar_dependencies' Jars.setup jar-dependencies-0.5.5/lib/jars/lock.rb0000644000004100000410000000303114770336505017742 0ustar www-datawww-data# frozen_string_literal: true require 'jars/maven_exec' module Jars class JarDetails < Array def scope self[-2].to_sym end def file file = self[-1].strip file.empty? ? path : file end def group_id self[0] end def artifact_id self[1] end def version self[-3] end def classifier return nil if size == 5 self[2] end def gacv classifier ? self[0..3] : self[0..2] end def path if scope == :system # replace maven like system properties embedded into the string self[-1].gsub(/\$\{[a-zA-Z.]+\}/) do |a| ENV_JAVA[a[2..-2]] || a end else File.join(Jars.home, group_id.gsub(/[.]/, '/'), artifact_id, version, "#{gacv[1..].join('-')}.jar") end end end class Lock def initialize(file) @file = file end def process(scope) scope ||= :runtime File.read(@file).each_line do |line| next unless /:.+:/.match?(line) jar = JarDetails.new(line.strip.sub(/:jar:/, ':').sub(/:$/, ': ').split(':')) case scope when :all, :test yield jar when :compile # jar.scope is maven scope yield jar if jar.scope != :test when :provided # jar.scope is maven scope yield jar if jar.scope == :provided when :runtime # jar.scope is maven scope yield jar if (jar.scope != :test) && (jar.scope != :provided) end end end end end jar-dependencies-0.5.5/lib/jars/maven_settings.rb0000644000004100000410000001103014770336505022036 0ustar www-datawww-data# frozen_string_literal: true module Jars class MavenSettings LINE_SEPARATOR = ENV_JAVA['line.separator'] class << self def local_settings @_jars_maven_local_settings_ = nil unless instance_variable_defined?(:@_jars_maven_local_settings_) if @_jars_maven_local_settings_.nil? settings = Jars.absolute('settings.xml') @_jars_maven_local_settings_ = if settings && File.exist?(settings) settings else false end end @_jars_maven_local_settings_ || nil end def user_settings @_jars_maven_user_settings_ = nil unless instance_variable_defined?(:@_jars_maven_user_settings_) if @_jars_maven_user_settings_.nil? if (settings = Jars.absolute(Jars.to_prop(MAVEN_SETTINGS))) unless File.exist?(settings) Jars.warn { "configured ENV['#{MAVEN_SETTINGS}'] = '#{settings}' not found" } settings = false end else # use maven default (user) settings settings = File.join(Jars.user_home, '.m2', 'settings.xml') settings = false unless File.exist?(settings) end @_jars_maven_user_settings_ = settings end @_jars_maven_user_settings_ || nil end def effective_settings @_jars_effective_maven_settings_ = nil unless instance_variable_defined?(:@_jars_effective_maven_settings_) if @_jars_effective_maven_settings_.nil? begin require 'rubygems/request' http = Gem::Request.proxy_uri(Gem.configuration[:http_proxy] || Gem::Request.get_proxy_from_env('http')) https = Gem::Request.proxy_uri(Gem.configuration[:https_proxy] || Gem::Request.get_proxy_from_env('https')) rescue Jars.debug('ignore rubygems proxy configuration as rubygems is too old') end @_jars_effective_maven_settings_ = if http.nil? && https.nil? settings else setup_interpolated_settings(http, https) || settings end end @_jars_effective_maven_settings_ end def cleanup File.unlink(effective_settings) if effective_settings != settings ensure reset end def reset instance_variables.each { |var| instance_variable_set(var, nil) } end def settings @_jars_maven_settings_ = nil unless instance_variable_defined?(:@_jars_maven_settings_) local_settings || user_settings if @_jars_maven_settings_.nil? end def global_settings @_jars_maven_global_settings_ = nil unless instance_variable_defined?(:@_jars_maven_global_settings_) if @_jars_maven_global_settings_.nil? if (mvn_home = ENV['M2_HOME'] || ENV['MAVEN_HOME']) settings = File.join(mvn_home, 'conf/settings.xml') settings = false unless File.exist?(settings) else settings = false end @_jars_maven_global_settings_ = settings end @_jars_maven_global_settings_ || nil end private def setup_interpolated_settings(http, https) proxy = raw_proxy_settings_xml(http, https).gsub("\n", LINE_SEPARATOR) if settings.nil? raw = "#{LINE_SEPARATOR}#{proxy}" else raw = File.read(settings) if raw.include?('') Jars.warn("can not interpolated proxy info for #{settings}") return else raw.sub!('', "#{LINE_SEPARATOR}#{proxy}") end end tempfile = java.io.File.create_temp_file('settings', '.xml') tempfile.delete_on_exit File.write(tempfile.path, raw) tempfile.path end def raw_proxy_settings_xml(http, https) raw = File.read(File.join(File.dirname(__FILE__), 'settings.xml')) if http raw.sub!('__HTTP_ACTIVE__', 'true') raw.sub!('__HTTP_SERVER__', http.host) raw.sub!('__HTTP_PORT__', http.port.to_s) else raw.sub!('__HTTP_ACTIVE__', 'false') end if https raw.sub!('__HTTPS_ACTIVE__', 'true') raw.sub!('__HTTPS_SERVER__', https.host) raw.sub!('__HTTPS_PORT__', https.port.to_s) else raw.sub!('__HTTPS_ACTIVE__', 'false') end raw end end end end jar-dependencies-0.5.5/lib/jar_install_post_install_hook.rb0000644000004100000410000000221014770336505024166 0ustar www-datawww-data# frozen_string_literal: true # # Copyright (C) 2014 Christian Meier # # Permission is hereby granted, free of charge, to any person obtaining a copy of # this software and associated documentation files (the "Software"), to deal in # the Software without restriction, including without limitation the rights to # use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of # the Software, and to permit persons to whom the Software is furnished to do so, # subject to the following conditions: # # The above copyright notice and this permission notice shall be included in all # copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS # FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR # COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER # IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN # CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # require 'jars/post_install_hook' jar-dependencies-0.5.5/jar-dependencies.gemspec0000644000004100000410000000261614770336505021535 0ustar www-datawww-data# frozen_string_literal: true require_relative 'lib/jars/version' Gem::Specification.new do |s| s.name = 'jar-dependencies' s.version = Jars::VERSION s.author = 'christian meier' s.email = ['mkristian@web.de'] s.summary = 'manage jar dependencies for gems' s.homepage = 'https://github.com/mkristian/jar-dependencies' s.bindir = 'exe' s.executables = [lock_jars = 'lock_jars'] s.license = 'MIT' s.files = Dir['{lib}/**/*'] + %w[Mavenfile Rakefile Readme.md jar-dependencies.gemspec MIT-LICENSE] s.description = <<~TEXT manage jar dependencies for gems and keep track which jar was already loaded using maven artifact coordinates. it warns on version conflicts and loads only ONE jar assuming the first one is compatible to the second one otherwise your project needs to lock down the right version by providing a Jars.lock file. TEXT s.required_ruby_version = '>= 2.6' s.add_development_dependency 'minitest', '~> 5.10' s.add_development_dependency 'ruby-maven', ruby_maven_version = '~> 3.9' s.post_install_message = <<~TEXT if you want to use the executable #{lock_jars} then install ruby-maven gem before using #{lock_jars} $ gem install ruby-maven -v '#{ruby_maven_version}' or add it as a development dependency to your Gemfile gem 'ruby-maven', '#{ruby_maven_version}' TEXT s.metadata['rubygems_mfa_required'] = 'true' end jar-dependencies-0.5.5/Rakefile0000644000004100000410000000043414770336505016431 0ustar www-datawww-data# frozen_string_literal: true task default: [:specs] require 'bundler/gem_tasks' require 'rubocop/rake_task' RuboCop::RakeTask.new desc 'run specs' task :specs do $LOAD_PATH << 'specs' Dir['specs/*_spec.rb'].each do |f| require File.basename(f.sub(/.rb$/, '')) end end jar-dependencies-0.5.5/MIT-LICENSE0000644000004100000410000000204314770336505016416 0ustar www-datawww-dataCopyright (c) 2014 Christian Meier Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. jar-dependencies-0.5.5/Readme.md0000644000004100000410000002317314770336505016510 0ustar www-datawww-data# jar-dependencies * [![Build Status](https://secure.travis-ci.org/mkristian/jar-dependencies.svg)](http://travis-ci.org/mkristian/jar-dependencies) * [![Code Climate](https://codeclimate.com/github/mkristian/jar-dependencies.svg)](https://codeclimate.com/github/mkristian/jar-dependencies) add gem dependencies for jar files to ruby gems. ## Getting control back over your jar jar dependencies are declared in the gemspec of the gem using the same notation as . When using `require_jar` to load the jar into JRuby's classloader a version conflict will be detected and only **ONE** jar gets loaded. **jbundler** allows to select the version suitable for you application. Most maven-artifacts do **NOT** use versions ranges but depend on a concrete version. In such cases **jbundler** can always **overwrite** any such version. ## Vendoring your jars before packing the jar Add the following to your *Rakefile*: require 'jars/installer' task :install_jars do Jars::Installer.vendor_jars! end This will install (download) the dependent jars into **JARS_HOME** and create a file **lib/my_gem_jars.rb**, which will be an enumeration of `require_jars` statements to load all the jars. The **vendor_jars** task will copy them into the **lib** directory of the gem. The location where jars are cached is per default **$HOME/.m2/repository** the same default as Maven uses to cache downloaded jar-artifacts. It respects **$HOME/.m2/settings.xml** from Maven with mirror and other settings or the environment variable **JARS_HOME**. **IMPORTANT**: Make sure that jar-dependencies is only a **development dependency** of your gem. If it is a runtime dependency the require_jars file will be overwritten during installation. ## Reduce the download and reuse the jars from maven local repository If you do not want to vendor jars into a gem then **jar-dependency** gem can vendor them when you install the gem. In that case do not use `Jars::Installer.install_jars` from the above rake tasks. **NOTE**: Recent JRuby comes with **jar-dependencies** as default gem, for older versions for the feature to work you need to gem install **jar-dependencies** first and for bundler need to use the **bundle-with-jars** command instead. **IMPORTANT**: Make sure that jar-dependencies is a **runtime dependency** of your gem so the require_jars file will be overwritten during installation with the "correct" versions of the jars. ## For development you do not need to vendor the jars at all Set the environment variable export JARS_VENDOR=false to tell the jar_installer not vendor any jars, but only create the file with the `require_jar` statements. This `require_jars` method will find the jar inside the maven local repository and load it from there. ## Some drawbacks * First you need to install the jar-dependency gem with its development dependencies installed (then ruby-maven gets installed as well) * Bundler does not install the jar-dependencies (unless JRuby adds the gem as default gem) * You need ruby-maven doing the job of dependency resolution and downloading them. gems not part of will not work currently ## JARs other than from maven-central By default all jars need to come from maven-central (), in order to use jars from any other repo you need to add it into your Maven *settings.xml* and configure it in a way that works without an interactive prompt (username + passwords needs to be part of the settings.xml file). **NOTE:** Gems depending on jars other then maven-central will **NOT** work when they get published on rubygems.org since the user of those gems will not have the right settings.xml to allow them to access the jar dependencies. ## Examples An [example with rspec and all](example/Readme.md) walks you through setup and shows how development works and shows what happens during installation. There are some more examples with the various [project setups for gems and application](examples/README.md). This includes using proper Maven for the project or ruby-maven with rake or the rake-compiler in conjunction with jar-dependencies. # Lock down versions Whenever there are version ranges for jar dependencies it is advisable to lock down the versions of dependencies. For the jar dependencies inside the gemspec declaration this can be done with: lock_jars This is also working in **any** project which uses a gem with jar-dependencies. It also uses a Jarfile if present. See the [sinatra application from the examples](examples/sinatra-app/having-jarfile-and-gems-with-jar-dependencies/). This means for a project using bundler and jar-dependencies the setup is bundle install lock_jars This will install both gems and jars for the project. Update a specific version is done with (use only the artifact_id) lock_jars --update slf4j-api And look at the dependencies tree lock_jars --tree As ```lock_jars``` uses ruby-maven to resolve the jar dependencies. Since jar-dependencies does not declare ruby-maven as runtime dependency (you just not need ruby-maven during runtime only when you want to setup the project it is needed) it is advicable to have it as development dependency in your Gemfile. # Proxy and mirror setup Proxies and mirrors can be set up by the usual configuration of maven itself: [settings.xml](https://maven.apache.org/settings.html) - see the mirrors and proxy sections. As jar-dependencies does only deal with jar and all jars need to come from maven central, it is only neccessary to mirror maven-central. An example of such a [settings-example.xml](setting.xml is here). You also can add such a settings.xml to your project which jar-dependencies will use instad of the default maven locations. This allows to have a per-project configuration and also removes the need to users of your Ruby project to dive into maven in case you have company policy to use a local mirror for gem and jar artifacts. jar-dependencies itself uses maven **only** for the jars and all gems are managed by RubyGems or Bundler or your favourite management tool. So any proxy/mirror settings which should affect gems need to be done in those tools. # Gradle, Maven, etc For dependency management frameworks like gradle (via jruby-gradle-plugin) or maven (via jruby-maven-plugins or jruby9-maven-plugins) or probably ivy or sbt can use the gem artifacts from a maven repository like [rubygems-proxy from torquebox](http://rubygems-proxy.torquebox.org/) or [rubygems.lasagna.io/proxy/maven/releases](http://rubygems.lasagna.io/proxy/maven/releases/). Each of these tools (including jar-dependencies) does the dependency resolution slightly different and in rare cases can produce different outcomes. But overall each tool can manage both jars and gems and their transitive dependencies. Popular gems like jrjackson or nokogiri do not declare their jars in the gemspec files and just load the bundle jars into jruby classloader, can easily create problems as the jackson and 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: JARS_VERBOSE=true bundle install JARS_VERBOSE=true gem install some_gem Or, with maven debug enabled 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: [https://github.com/takari/polyglot-maven#configuration](polyglot-maven configuration) where ```${maven.multiModuleProjectDirectory}``` is your current directory. # Configuration
ENVjava system propertydefaultdescription
JARS_DEBUGjars.debugfalseif set to true it will produce lots of debug out (maven -X switch)
JARS_VERBOSEjars.verbosefalseif set to true it will produce some extra output
JARS_HOMEjars.home$HOME/.m2/repositoryfilesystem location where to store the jar files and some metadata
JARS_MAVEN_SETTINGSjars.maven.settings$HOME/.m2/settings.xmlsetting.xml for maven to use
JARS_VENDORjars.vendortrueset to true means that the jars will be stored in JARS_HOME only
JARS_SKIPjars.skiptruedo **NOT** install jar dependencies at all
# Motivation Just today, I stumbled across [https://github.com/arrigonialberto86/ruby-band](https://github.com/arrigonialberto86/ruby-band) which uses jbundler to manage their JAR dependencies, which happens on the first 'require "ruby-band"'. There is no easy or formal way to find out which JARs are added to jruby-classloader. Another issue was brought to my notice yesterday [https://github.com/hqmq/derelicte/issues/1](https://github.com/hqmq/derelicte/issues/1). Or the question of how to manage JRuby projects with maven [http://ruby.11.x6.nabble.com/Maven-dependency-management-td4996934.html](http://ruby.11.x6.nabble.com/Maven-dependency-management-td4996934.html) Or a few days ago an issue for rake-compile [https://github.com/luislavena/rake-compiler/issues/87](https://github.com/luislavena/rake-compiler/issues/87) With JRuby 9000 it is the right time to get jar dependencies "right" - the current situation is like the time before bundler for gems. # Developing You must have the latest ruby-maven installed in your local JRuby. ./mvnw install will build the gem and run integration tests jar-dependencies-0.5.5/Mavenfile0000644000004100000410000000372214770336505016620 0ustar www-datawww-data# frozen_string_literal: true gemfile plugin_repository id: :mavengems, url: 'mavengem:https://rubygems.org' jruby_plugin(:minitest, minispecDirectory: 'specs/*_spec.rb') do execute_goals(:spec) gem 'ruby-maven', '${ruby-maven.version}' end # retrieve the ruby-maven version gemfile_profile = @model.profiles.detect do |p| p.id.to_sym == :gemfile end || @model ruby_maven = gemfile_profile.dependencies.detect do |d| d.artifact_id == 'ruby-maven' end properties('jruby.versions' => ['${jruby.version}'].join(','), # just lock the version 'bundler.version' => '2.5.11', 'ruby-maven.version' => ruby_maven.version, 'jruby.version' => '9.4.8.0', 'jruby.plugins.version' => '3.0.2', 'push.skip' => true) plugin :invoker, '1.8' do execute_goals(:install, :run, id: 'integration-tests', projectsDirectory: 'integration', streamLogs: true, goals: ['install'], preBuildHookScript: 'setup.bsh', postBuildHookScript: 'verify.bsh', cloneProjectsTo: '${project.build.directory}', properties: { 'jar-dependencies.version' => '${project.version}', # use an old jruby with old ruby-maven here 'jruby.version' => '${jruby.version}', 'jruby.plugins.version' => '${jruby.plugins.version}', 'bundler.version' => '${bundler.version}', 'ruby-maven.version' => '${ruby-maven.version}' }) end distribution_management do repository id: :ossrh, url: 'https://oss.sonatype.org/service/local/staging/deploy/maven2/' end profile id: :skip do properties 'maven.test.skip' => true, 'invoker.skip' => true end profile id: :release do properties 'maven.test.skip' => true, 'invoker.skip' => true, 'push.skip' => false build do default_goal :deploy end end