jarbler 0.1.3 → 0.1.4

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: fa38516809660fd2add2d7f1cb4a47bf48f219afb69adc2242f582c96b3b7a6f
4
- data.tar.gz: 8f6cca1c0fbf6e892f7db511ba012de9fb9f3c96bfa49079e373172f0c9ee64a
3
+ metadata.gz: 69c4dfd51fa32af943ab9ada29536253dc516150cdff7e82e1944216098a92c8
4
+ data.tar.gz: 63e6752eba98d7cc27642fcbb13a199fc41867a6d044edf28051f025d292ef09
5
5
  SHA512:
6
- metadata.gz: 3b01cbb87353587184e147d9082e5c8a4807afec0308a940c6c53c4b65a9df13aaa1eac32e1a0615fd0f4716c9e5d49b0a7138895dc5857f40f9c31f3de2fe6d
7
- data.tar.gz: 1ab3a61b970c11b13e2ad118507dee7463460baf11c4d2dc617babf85f4e253206952245d5dbbcc1cb42356143b17d90fe3594c35564aa91b6462c49da862020
6
+ metadata.gz: 882f6b8e791b8f7fc9cc4eff3d86867c2667f8d817fd4c46a1f10103bcf98e50aee1e98c10b49fe14ae5e4f5a63a992ff9bf9121d4a9459d87e20ca05560c42a
7
+ data.tar.gz: e8b9a10dbfacc4180710a62fe84cfa9595049d62cd6ff6625cf520d39d380357f13502f0e0f228057d85d226d4ef29fe255e5cc63cf011f5d00f92bc8c5d2c52
data/CHANGELOG.md CHANGED
@@ -15,3 +15,7 @@
15
15
  ## [0.1.3] - 2023-04-25
16
16
 
17
17
  - Removed .jruby-version so that the jruby version is not fixed anymore
18
+
19
+ ## [0.1.4] - 2023-04-28
20
+
21
+ - Jarbler also supports Gemfile references to Gems with git dependencies now
data/Gemfile CHANGED
@@ -8,10 +8,11 @@ gemspec
8
8
  # gem "rake", "~> 13.0"
9
9
  gem "rake"
10
10
 
11
+ group(:development) do
12
+ gem 'rdoc'
13
+ end
14
+
11
15
  group(:test) do
12
16
  gem 'minitest'
13
17
  gem 'minitest-reporters'
14
- # needed for minitests
15
- # test should install the jruby-jars in right version itself
16
- # gem 'jruby-jars'
17
18
  end
data/README.md CHANGED
@@ -1,11 +1,10 @@
1
1
  # Jarbler
2
2
  Pack a Ruby application into an executable jar file.
3
3
 
4
- Jarbler allows you to create an self executing Java jar file containing your Ruby application.
4
+ Jarbler creates a self executing Java jar file containing a Ruby application and all its Gem dependencies.
5
5
 
6
6
  This tool is inspired by the widely used jRuby runner Warbler.
7
- In contrast to Warbler no Java servlet container is needed for execution.
8
- Instead the configured executable is executed using the jRuby runtime jars.
7
+ The configured Ruby program is directly executed inside the JVM using the jRuby runtime jars.
9
8
 
10
9
  ## Installation
11
10
 
@@ -28,6 +27,7 @@ To adjust Jarbler's configuration, modify the settings in config file ´config/j
28
27
  $ jarble config
29
28
 
30
29
  ### Preconditions
30
+ * Dependency handling should be based on Bundler (existence of Gemfile is required)
31
31
  * The Ruby app should be capable of running with jRuby
32
32
  * Gems with native extensions should not be used (e.g. sassc)
33
33
  * if needed for development or test such Gems with native extensions should be moved to the development and test group in the Gemfile.
@@ -43,7 +43,7 @@ Additional command line parameters are passed through to the executed Ruby app (
43
43
  ## Configuration
44
44
 
45
45
  The file config/jarble.rb contains the configuration for Jarbler.
46
- To create a template config file with information about the supported configuration options, execute:
46
+ To create a template config file with information about all the supported configuration options, execute:
47
47
 
48
48
  $ jarble config
49
49
 
data/jarbler.gemspec CHANGED
@@ -9,7 +9,7 @@ Gem::Specification.new do |spec|
9
9
  spec.email = ["Peter@ramm-oberhermsdorf.de"]
10
10
 
11
11
  spec.summary = "Pack a Ruby app into a Java jar file"
12
- spec.description = "Pack Ruby combined with jRuby runtime into a jar file to simply run the app on any Java platform by '> java -jar file.jar'"
12
+ spec.description = "Pack a Ruby app combined with jRuby runtime and all its Gem dependencies into a jar file to simply run the app on any Java platform by '> java -jar file.jar'"
13
13
  spec.homepage = "https://github.com/rammpeter/jarbler"
14
14
  spec.license = "MIT"
15
15
  spec.required_ruby_version = ">= 2.6.0"
@@ -27,13 +27,16 @@ import java.util.Map;
27
27
  import java.util.HashMap;
28
28
  import java.lang.reflect.Field;
29
29
  import java.io.FileWriter;
30
+ import java.security.CodeSource;
31
+ import java.security.ProtectionDomain;
30
32
 
31
33
  class JarMain {
32
34
 
33
35
  // executed by java -jar <jar file name>
34
36
  // No arguments are passed
35
37
  public static void main(String[] args) {
36
- debug("Start java process in jar file");
38
+ debug("Start java process in jar file "+jar_file_name());
39
+ debug("JVM: "+System.getProperty("java.vm.vendor")+" "+System.getProperty("java.vm.name")+" "+System.getProperty("java.vm.version")+" "+System.getProperty("java.home"));
37
40
  if (args.length > 0) {
38
41
  debug("Java command line arguments are: ");
39
42
  for (String arg : args) {
@@ -225,4 +228,18 @@ class JarMain {
225
228
  fw.write("BUNDLE_WITHOUT: test:development\n");
226
229
  fw.close();
227
230
  }
231
+
232
+ private static String jar_file_name() {
233
+ String jarFileName = "";
234
+
235
+ try {
236
+ ProtectionDomain protectionDomain = JarMain.class.getProtectionDomain();
237
+ CodeSource codeSource = protectionDomain.getCodeSource();
238
+ URL location = codeSource.getLocation();
239
+ jarFileName = new File(location.toURI()).getName();
240
+ } catch (Exception e) {
241
+ e.printStackTrace();
242
+ }
243
+ return jarFileName;
244
+ }
228
245
  }
@@ -13,9 +13,8 @@ module Jarbler
13
13
  def build_jar
14
14
  debug "Running with Ruby version '#{RUBY_VERSION}' on platform '#{RUBY_PLATFORM}'. Engine '#{RUBY_ENGINE}' version '#{RUBY_ENGINE_VERSION}'"
15
15
 
16
- # create a temporary directory for staging
17
- staging_dir = Dir.mktmpdir
18
-
16
+ @config = nil # Ensure config is read from file or default. Necessary for testing only because of caching
17
+ staging_dir = Dir.mktmpdir # create a temporary directory for staging
19
18
  app_root = Dir.pwd
20
19
  debug "Project dir: #{app_root}"
21
20
 
@@ -31,12 +30,8 @@ module Jarbler
31
30
  # Get the needed Gems
32
31
  raise "Gemfile.lock not found in #{app_root}" unless File.exist?("#{app_root}/Gemfile.lock")
33
32
 
34
- gem_target_location = "#{staging_dir}/gems/jruby/#{ruby_version}"
35
- FileUtils.mkdir_p("#{gem_target_location}/gems")
36
- FileUtils.mkdir_p("#{gem_target_location}/specifications")
37
-
38
33
  # Copy the needed Gems to the staging directory
39
- copy_needed_gems_to_staging(gem_target_location, app_root)
34
+ copy_needed_gems_to_staging(staging_dir, ruby_version)
40
35
 
41
36
  Dir.chdir(staging_dir) do
42
37
  # create the manifest file
@@ -73,16 +68,25 @@ module Jarbler
73
68
  file_utils_copy(config.jar_name, app_root)
74
69
  puts "Created jar file #{app_root}/#{config.jar_name}"
75
70
  end
76
-
71
+ rescue Exception => e
72
+ puts "Error: #{e.message}"
73
+ puts e.backtrace.join("\n")
74
+ raise
75
+ ensure
77
76
  # remove temporary directory staging_dir
78
- FileUtils.remove_entry staging_dir
79
-
77
+ if ENV['DEBUG']
78
+ puts "Temporary directory #{staging_dir} not removed because of debug mode"
79
+ else
80
+ FileUtils.remove_entry staging_dir if staging_dir
81
+ end
80
82
  end
81
83
 
82
84
  private
83
85
 
84
86
 
85
87
  # Check if there is an additional local bundle path in .bundle/config
88
+ # @param rails_root [String] the rails root directory
89
+ # @return [String] the local bundle path or nil if not configured
86
90
  def bundle_config_bundle_path(rails_root)
87
91
  bundle_path = nil # default
88
92
  if File.exist?("#{rails_root}/.bundle/config")
@@ -96,30 +100,41 @@ module Jarbler
96
100
  end
97
101
 
98
102
  # Copy the needed Gems to the staging directory
99
- # @param [String] gem_target_location Path to the staging directory
103
+ # @param staging_dir [String] the staging directory
104
+ # @param ruby_version [String] the corresponding ruby version of the jruby jars version
100
105
  # @return [void]
101
- def copy_needed_gems_to_staging(gem_target_location, app_root)
102
- #Bundler.with_unbundled_env do # No previous setting inherited like Gemfile location
103
- # Bundler.reset! # Reset settings from previous Bundler.with_unbundled_env
104
- needed_gems = gem_dependencies # get the full names of the dependencies
105
- needed_gems.each do |needed_gem|
106
- # Get the location of the needed gem
107
- spec = Gem::Specification.find_by_name(needed_gem[:name], needed_gem[:version])
108
- raise "Gem #{needed_gem[:full_name]} not found for copying" unless spec
109
- debug "Found gem #{needed_gem[:full_name]} version #{needed_gem[:version]} in #{spec.gem_dir}"
106
+ def copy_needed_gems_to_staging(staging_dir, ruby_version)
107
+ gem_target_location = "#{staging_dir}/gems/jruby/#{ruby_version}"
108
+ FileUtils.mkdir_p("#{gem_target_location}/gems")
109
+ FileUtils.mkdir_p("#{gem_target_location}/specifications")
110
+ FileUtils.mkdir_p("#{gem_target_location}/bundler/gems")
111
+
112
+ needed_gems = gem_dependencies # get the full names of the dependencies
113
+ needed_gems.each do |needed_gem|
114
+ # Get the location of the needed gem
115
+ spec = Gem::Specification.find_by_name(needed_gem[:name], needed_gem[:version])
116
+ raise "Gem #{needed_gem[:full_name]} not found for copying" unless spec
117
+ debug "Found gem #{needed_gem[:full_name]} version #{needed_gem[:version]} in #{spec.gem_dir}"
118
+
119
+ # differentiate between Gems from git/bundler and Gems from rubygems
120
+ if spec.source.is_a?(Bundler::Source::Git)
121
+ # Copy the Gem from bundler/gems including the gemspec
122
+ file_utils_copy(spec.gem_dir, "#{gem_target_location}/bundler/gems")
123
+ else # Gem is from rubygems
124
+ # copy the Gem and gemspec separately
110
125
  file_utils_copy(spec.gem_dir, "#{gem_target_location}/gems")
111
126
  file_utils_copy("#{spec.gem_dir}/../../specifications/#{needed_gem[:full_name]}.gemspec", "#{gem_target_location}/specifications")
112
- # end
127
+ end
113
128
  end
114
129
  end
115
130
 
116
131
  # Read the default/production dependencies from Gemfile.lock and Gemfile
117
- # @return [Array] Array with full names of dependencies
132
+ # @return [Array] Array with Hashes containing: name, version, full_name
118
133
  def gem_dependencies
119
134
  needed_gems = []
120
135
  lockfile_specs = Bundler::LockfileParser.new(Bundler.read_file(Bundler.default_lockfile)).specs
121
136
 
122
- # Bundler.setup # Load Gems specified in Gemfile
137
+ Bundler.setup # Load Gems specified in Gemfile, ensure that Gem path also includes the Gems loaded into bundler dir
123
138
  # filter Gems needed for production
124
139
  gemfile_specs = Bundler.definition.dependencies.select do |d|
125
140
  d.groups.include?(:default) || d.groups.include?(:production)
@@ -145,7 +160,7 @@ module Jarbler
145
160
  # recurively find all indirect dependencies
146
161
  # @param [Array] lockfile_specs Array of Bundler::LockfileParser::Spec objects
147
162
  # @param [Bundler::LockfileParser::Spec] lockfile_spec current lockfile spec to check for their dependencies
148
- # @param [Array] needed_gems Array with full names of already found dependencies, add findings here
163
+ # @param [Array] needed_gems Array with Hashes containing: name, version, full_name
149
164
  # @return [void]
150
165
  def add_indirect_dependencies(lockfile_specs, lockfile_spec, needed_gems)
151
166
  lockfile_spec.dependencies.each do |lockfile_spec_dep|
@@ -161,12 +176,18 @@ module Jarbler
161
176
  end
162
177
  end
163
178
  end
179
+
180
+ # Output debug message if DEBUG environment variable is set
181
+ # @param [String] msg Message to output
182
+ # @return [void]
164
183
  def debug(msg)
165
184
  puts msg if ENV['DEBUG']
166
185
  end
167
186
 
187
+ # Get the config object
188
+ # @return [Config] the config object
168
189
  def config
169
- unless defined? @config
190
+ if !defined?(@config) || @config.nil?
170
191
  @config = Config.create
171
192
  debug("Config attributes:")
172
193
  @config.instance_variables.each do |var|
@@ -179,7 +200,6 @@ module Jarbler
179
200
 
180
201
  # Copy the jruby-jars to the staging directory
181
202
  # @param [String] staging_dir Path to the staging directory
182
- # @param [Array] gem_search_locations Array of Gem locations to look for jRuby jars
183
203
  # @return [String] the ruby version of the jRuby jars
184
204
  def copy_jruby_jars_to_staging(staging_dir)
185
205
 
@@ -207,7 +227,9 @@ module Jarbler
207
227
  ruby_version
208
228
  end
209
229
 
210
- # Execute the command and return the output
230
+ # Execute the command in OS and return the output
231
+ # @param [String] command Command to execute
232
+ # @return [String] the output of the command
211
233
  def exec_command(command)
212
234
  lines = `#{command}`
213
235
  raise "Command \"#{command}\"failed with return code #{$?} and output:\n#{lines}" unless $?.success?
@@ -216,6 +238,9 @@ module Jarbler
216
238
  end
217
239
 
218
240
  # Copy file or directory with error handling
241
+ # @param [String] source Path to the source file or directory
242
+ # @param [String] destination Path to the destination file or directory
243
+ # @return [void]
219
244
  def file_utils_copy(source, destination)
220
245
  if File.exist?(source) && File.directory?(source)
221
246
  FileUtils.cp_r(source, destination)
@@ -1,9 +1,12 @@
1
+ require 'rubygems'
2
+ require 'json'
3
+
1
4
  module Jarbler
2
5
  class Config
3
6
  attr_accessor :jar_name, :includes, :excludes, :jruby_version, :executable, :executable_params
4
7
 
5
8
  CONFIG_FILE = 'config/jarble.rb'
6
- # create instence of Config class with defaults or from config file
9
+ # create instance of Config class with defaults or from config file
7
10
  # Should be called from rails/ruby root directory
8
11
  def self.create
9
12
  if File.exist?(CONFIG_FILE)
@@ -90,12 +93,18 @@ module Jarbler
90
93
  else
91
94
  # no .ruby-version file, use jRuby version of the latest Gem
92
95
  # Fetch the gem specification from Rubygems.org
93
- command = "gem search --remote jruby-jars"
94
- lines = `#{command}`
95
- raise "Command \"#{command}\" failed with return code #{$?} and output:\n#{lines}" unless $?.success?
96
- jruby_jars_line = lines.match(/^jruby-jars \((.*)\)/)
97
- raise "No jruby-jars gem found in rubygems.org!" unless jruby_jars_line
98
- self.jruby_version = /\((.*?)\)/.match(jruby_jars_line.to_s)[1]
96
+ # search for the gem and get the JSON response
97
+ response = Gem::SpecFetcher.fetcher.search_for_dependency(Gem::Dependency.new('jruby-jars'))
98
+ # extract the versions from the response
99
+ self.jruby_version = response&.first&.first&.first&.version&.to_s
100
+ raise "Unable to determine the latest available version of jruby-jars gem!\Rsponse = #{response.inspect}" unless self.jruby_version
101
+
102
+ #command = "gem search --remote jruby-jars"
103
+ #lines = `#{command}`
104
+ #raise "Command \"#{command}\" failed with return code #{$?} and output:\n#{lines}" unless $?.success?
105
+ #jruby_jars_line = lines.match(/^jruby-jars \((.*)\)/)
106
+ #raise "No jruby-jars gem found in rubygems.org!" unless jruby_jars_line
107
+ #self.jruby_version = /\((.*?)\)/.match(jruby_jars_line.to_s)[1]
99
108
  debug "jRuby version from latest jruby-jars gem: #{jruby_version}"
100
109
  end
101
110
  end
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Jarbler
4
- VERSION = "0.1.3"
5
- VERSION_DATE = "2023-04-25"
4
+ VERSION = "0.1.4"
5
+ VERSION_DATE = "2023-04-28"
6
6
  end
metadata CHANGED
@@ -1,17 +1,17 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: jarbler
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.3
4
+ version: 0.1.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Peter Ramm
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-04-26 00:00:00.000000000 Z
11
+ date: 2023-04-28 00:00:00.000000000 Z
12
12
  dependencies: []
13
- description: Pack Ruby combined with jRuby runtime into a jar file to simply run the
14
- app on any Java platform by '> java -jar file.jar'
13
+ description: Pack a Ruby app combined with jRuby runtime and all its Gem dependencies
14
+ into a jar file to simply run the app on any Java platform by '> java -jar file.jar'
15
15
  email:
16
16
  - Peter@ramm-oberhermsdorf.de
17
17
  executables: