lib/jarbler/builder.rb in jarbler-0.1.2 vs lib/jarbler/builder.rb in jarbler-0.1.3

- old
+ new

@@ -1,27 +1,28 @@ +require 'rubygems' +require 'rubygems/dependency_installer' require 'bundler' require 'find' require 'fileutils' +require 'yaml' module Jarbler class Builder # Execute all functions needed to build the jar file # Should be executed in application directory of Rails/Ruby application # @return [void] def build_jar + debug "Running with Ruby version '#{RUBY_VERSION}' on platform '#{RUBY_PLATFORM}'. Engine '#{RUBY_ENGINE}' version '#{RUBY_ENGINE_VERSION}'" + # create a temporary directory for staging staging_dir = Dir.mktmpdir - jarbler_lib_dir = __dir__ app_root = Dir.pwd debug "Project dir: #{app_root}" - # TODO: transform to internal bundler API call (check if jruby is installed + install if not) - exec_command "gem install --no-doc jruby-jars -v #{config.jruby_version}" # Ensure that jruby-jars are installed in the requested version - gem_search_locations = collect_gem_search_locations(app_root) - ruby_version = copy_jruby_jars_to_staging(staging_dir, gem_search_locations) # Copy the jruby jars to the staging directory - exec_command "javac -nowarn -Xlint:deprecation -source 8 -target 8 -d #{staging_dir} #{jarbler_lib_dir}/JarMain.java" # Compile the Java files + ruby_version = copy_jruby_jars_to_staging(staging_dir) # Copy the jruby jars to the staging directory + exec_command "javac -nowarn -Xlint:deprecation -source 8 -target 8 -d #{staging_dir} #{__dir__}/JarMain.java" # Compile the Java files # Copy the application project to the staging directory FileUtils.mkdir_p("#{staging_dir}/app_root") config.includes.each do |dir| file_utils_copy("#{app_root}/#{dir}", "#{staging_dir}/app_root") if File.exist?("#{app_root}/#{dir}") @@ -32,14 +33,12 @@ gem_target_location = "#{staging_dir}/gems/jruby/#{ruby_version}" FileUtils.mkdir_p("#{gem_target_location}/gems") FileUtils.mkdir_p("#{gem_target_location}/specifications") - needed_gems = gem_dependencies # get the full names of the dependencies - needed_gems.each do |gem_full_name| - copy_gem_to_staging(gem_full_name, gem_target_location, gem_search_locations) - end + # Copy the needed Gems to the staging directory + copy_needed_gems_to_staging(gem_target_location, app_root) Dir.chdir(staging_dir) do # create the manifest file File.open('Manifest.txt', 'w') do |file| file.write("Comment: created by Jarbler (https://github.com/rammpeter/jarbler)\n") @@ -80,84 +79,69 @@ end private - # Find the locations where Gems are installed - # @param [String] app_root Application root directory - # @return [Array] Array of Gem locations - def collect_gem_search_locations(app_root) - # All active search locations for Gems - Bundler.setup - possible_gem_search_locations = Gem.paths.path - debug "Possible Gem locations: #{possible_gem_search_locations}" - gem_search_locations = [] - # Check where inside this location the gems may be installed - possible_gem_search_locations.each do |gem_search_location| - if File.exist?(gem_search_location) && File.directory?(gem_search_location) - valid_gem_search_location = nil # No valid path found yet - Find.find(gem_search_location) do |path| - if File.directory?(path) && File.exist?("#{path}/specifications") && File.exist?("#{path}/gems") - valid_gem_search_location = path # Found a valid path - Find.prune # Do not search deeper - end - end - if valid_gem_search_location - gem_search_locations << valid_gem_search_location - else - debug "No valid gem location found in #{gem_search_location}" - end - else - debug("Gem location #{gem_search_location} does not exist or is not a directory") + + # Check if there is an additional local bundle path in .bundle/config + def bundle_config_bundle_path(rails_root) + bundle_path = nil # default + if File.exist?("#{rails_root}/.bundle/config") + bundle_config = YAML.load_file("#{rails_root}/.bundle/config") + if bundle_config && bundle_config['BUNDLE_PATH'] + bundle_path = "#{rails_root}/#{bundle_config['BUNDLE_PATH']}" + debug "Local Gem path configured in #{rails_root}/.bundle/config: #{bundle_path}" end end - debug "Valid Gem locations: #{gem_search_locations}" - gem_search_locations + bundle_path end - # Copy the Gem elements to the staging directory - # @param [String] gem_full_name Full name of the Gem including version and platform - # @param [String] staging_dir Path to the staging directory - # @param [Array] gem_search_locations Array of Gem locations + # Copy the needed Gems to the staging directory + # @param [String] gem_target_location Path to the staging directory # @return [void] - def copy_gem_to_staging(gem_full_name, gem_target_location, gem_search_locations) - gem_search_locations.each do |gem_search_location| - gem_dir = "#{gem_search_location}/gems/#{gem_full_name}" - if File.exist?(gem_dir) - file_utils_copy(gem_dir, "#{gem_target_location}/gems") - file_utils_copy("#{gem_search_location}/specifications/#{gem_full_name}.gemspec", "#{gem_target_location}/specifications") - return - end + def copy_needed_gems_to_staging(gem_target_location, app_root) + #Bundler.with_unbundled_env do # No previous setting inherited like Gemfile location + # Bundler.reset! # Reset settings from previous Bundler.with_unbundled_env + needed_gems = gem_dependencies # get the full names of the dependencies + needed_gems.each do |needed_gem| + # Get the location of the needed gem + spec = Gem::Specification.find_by_name(needed_gem[:name], needed_gem[:version]) + raise "Gem #{needed_gem[:full_name]} not found for copying" unless spec + debug "Found gem #{needed_gem[:full_name]} version #{needed_gem[:version]} in #{spec.gem_dir}" + file_utils_copy(spec.gem_dir, "#{gem_target_location}/gems") + file_utils_copy("#{spec.gem_dir}/../../specifications/#{needed_gem[:full_name]}.gemspec", "#{gem_target_location}/specifications") + # end end - raise "Gem #{gem_name} (#{gem_version}) not found in any of the following locations:\n#{gem_search_locations.join("\n")}" end # Read the default/production dependencies from Gemfile.lock and Gemfile # @return [Array] Array with full names of dependencies def gem_dependencies needed_gems = [] lockfile_specs = Bundler::LockfileParser.new(Bundler.read_file(Bundler.default_lockfile)).specs - Bundler.setup # Load Gems specified in Gemfile + # Bundler.setup # Load Gems specified in Gemfile # filter Gems needed for production gemfile_specs = Bundler.definition.dependencies.select do |d| d.groups.include?(:default) || d.groups.include?(:production) end debug "Gems from Gemfile needed for production:" gemfile_specs.each do |gemfile_spec| # find lockfile record for Gemfile spec lockfile_spec = lockfile_specs.find { |lockfile_spec| lockfile_spec.name == gemfile_spec.name } if lockfile_spec - needed_gems << lockfile_spec.full_name unless needed_gems.include?(lockfile_spec.full_name) + unless needed_gems.map{|n| n[:fullname]}.include?(lockfile_spec.full_name) + needed_gems << { full_name: lockfile_spec.full_name, name: lockfile_spec.name, version: lockfile_spec.version } + end debug "Direct Gem dependency: #{lockfile_spec.full_name}" add_indirect_dependencies(lockfile_specs, lockfile_spec, needed_gems) else debug "Gem #{gemfile_spec.name} not found in Gemfile.lock" end end - needed_gems.uniq.sort + needed_gems.uniq.sort{|a,b| a[:full_name] <=> b[:full_name]} end # recurively find all indirect dependencies # @param [Array] lockfile_specs Array of Bundler::LockfileParser::Spec objects # @param [Bundler::LockfileParser::Spec] lockfile_spec current lockfile spec to check for their dependencies @@ -166,12 +150,12 @@ def add_indirect_dependencies(lockfile_specs, lockfile_spec, needed_gems) lockfile_spec.dependencies.each do |lockfile_spec_dep| lockfile_spec_found = lockfile_specs.find { |lockfile_spec| lockfile_spec.name == lockfile_spec_dep.name } if lockfile_spec_found debug "Indirect Gem dependency from #{lockfile_spec.full_name}: #{lockfile_spec_found.full_name}" - unless needed_gems.include?(lockfile_spec_found.full_name) - needed_gems << lockfile_spec_found.full_name + unless needed_gems.map{|n| n[:fullname]}.include?(lockfile_spec_found.full_name) + needed_gems << { full_name: lockfile_spec_found.full_name, name: lockfile_spec_found.name, version: lockfile_spec_found.version } add_indirect_dependencies(lockfile_specs, lockfile_spec_found, needed_gems) end else debug "Gem #{lockfile_spec_dep.name} not found in Gemfile.lock" end @@ -195,19 +179,23 @@ # Copy the jruby-jars to the staging directory # @param [String] staging_dir Path to the staging directory # @param [Array] gem_search_locations Array of Gem locations to look for jRuby jars # @return [String] the ruby version of the jRuby jars - def copy_jruby_jars_to_staging(staging_dir, gem_search_locations) - jruby_jars_location = nil - gem_search_locations.each do |gem_search_location| - gem_dir = "#{gem_search_location}/gems/jruby-jars-#{config.jruby_version}" - if File.exist?(gem_dir) - jruby_jars_location = gem_dir - break - end - end - raise "Could not determine location of jRuby jars for release '#{config.jruby_version}' in the following locations:\n#{gem_search_locations}" unless jruby_jars_location + def copy_jruby_jars_to_staging(staging_dir) + + # Ensure that jruby-jars gem is installed, otherwise install it. Accepts also bundler path in .bundle/config + installer = Gem::DependencyInstaller.new + installed = installer.install('jruby-jars', config.jruby_version) + raise "jruby-jars gem not installed in version #{config.jruby_version}" if installed.empty? + + jruby_jars_location = installed[0]&.full_gem_path + debug "jRuby jars installed at: #{jruby_jars_location}" + + # Get the location of the jruby-jars gem + # spec = Gem::Specification.find_by_name('jruby-jars', config.jruby_version) + # jruby_jars_location = spec.gem_dir + file_utils_copy("#{jruby_jars_location}/lib/jruby-core-#{config.jruby_version}-complete.jar", staging_dir) file_utils_copy("#{jruby_jars_location}/lib/jruby-stdlib-#{config.jruby_version}.jar", staging_dir) # Get the according Ruby version for the current jRuby version lines = exec_command "java -cp #{jruby_jars_location}/lib/jruby-core-#{config.jruby_version}-complete.jar org.jruby.Main --version" \ No newline at end of file