jarbler 0.1.3 → 0.1.5

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: fa38516809660fd2add2d7f1cb4a47bf48f219afb69adc2242f582c96b3b7a6f
4
- data.tar.gz: 8f6cca1c0fbf6e892f7db511ba012de9fb9f3c96bfa49079e373172f0c9ee64a
3
+ metadata.gz: d5166483687f2467695c869afc03f491134d1bd74004d97ba706b1296f6836d1
4
+ data.tar.gz: 59d98964583486160c572d7c2ee8326f6f005a3cab558bd95b9114c5954a83eb
5
5
  SHA512:
6
- metadata.gz: 3b01cbb87353587184e147d9082e5c8a4807afec0308a940c6c53c4b65a9df13aaa1eac32e1a0615fd0f4716c9e5d49b0a7138895dc5857f40f9c31f3de2fe6d
7
- data.tar.gz: 1ab3a61b970c11b13e2ad118507dee7463460baf11c4d2dc617babf85f4e253206952245d5dbbcc1cb42356143b17d90fe3594c35564aa91b6462c49da862020
6
+ metadata.gz: 5230dc737fd40641ee5fc2babaf5a982c5768f0d3281ad5fa384c3c9cc1814c575b33e906d69607a401475a1f46932be507dbed2b12fd28ba0c244bd84b10564
7
+ data.tar.gz: d6226dd8aa0c658eacc18caa868c0084232267f04c99f968d01ea88e0f929fa5c9cd94fab39b7f76cca3a934f46e5797e86afbd165fbba6c1e9f8b2fb381e83b
data/CHANGELOG.md CHANGED
@@ -1,17 +1,29 @@
1
1
  ## [Unreleased]
2
2
 
3
- ## [0.1.0] - 2023-04-12
3
+ ## [0.1.5] - 2023-06-15
4
4
 
5
- - Initial release
5
+ - Bugfix: use minor ruby version without patch level for Gem files location
6
+
7
+ ## [0.1.4] - 2023-04-28
8
+
9
+ - Jarbler also supports Gemfile references to Gems with git dependencies now
10
+
11
+ ## [0.1.3] - 2023-04-25
12
+
13
+ - Removed .jruby-version so that the jruby version is not fixed anymore
14
+
15
+ ## [0.1.2] - 2023-04-24
16
+
17
+ - extract valid Gem paths from Bundler instead of using the environment variable GEM_PATH
6
18
 
7
19
  ## [0.1.1] - 2023-04-24
8
20
 
9
21
  - Fixed the bug 'java.lang.ClassNotFoundException: org.jruby.Main' with Windows
10
22
 
11
- ## [0.1.2] - 2023-04-24
23
+ ## [0.1.0] - 2023-04-12
24
+
25
+ - Initial release
26
+
12
27
 
13
- - extract valid Gem paths from Bundler instead of using the environment variable GEM_PATH
14
28
 
15
- ## [0.1.3] - 2023-04-25
16
29
 
17
- - Removed .jruby-version so that the jruby version is not fixed anymore
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
 
@@ -16,6 +15,8 @@ Install the gem and add to the application's Gemfile by executing:
16
15
  If bundler is not being used to manage dependencies, install the gem by executing:
17
16
 
18
17
  $ gem install jarbler
18
+
19
+ [![Gem Version](https://badge.fury.io/rb/jarbler.svg)](https://badge.fury.io/rb/jarbler)
19
20
 
20
21
  ## Usage
21
22
 
@@ -28,6 +29,7 @@ To adjust Jarbler's configuration, modify the settings in config file ´config/j
28
29
  $ jarble config
29
30
 
30
31
  ### Preconditions
32
+ * Dependency handling should be based on Bundler (existence of Gemfile is required)
31
33
  * The Ruby app should be capable of running with jRuby
32
34
  * Gems with native extensions should not be used (e.g. sassc)
33
35
  * if needed for development or test such Gems with native extensions should be moved to the development and test group in the Gemfile.
@@ -43,13 +45,22 @@ Additional command line parameters are passed through to the executed Ruby app (
43
45
  ## Configuration
44
46
 
45
47
  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:
48
+ To create a template config file with information about all the supported configuration options, execute:
47
49
 
48
50
  $ jarble config
49
51
 
50
- The default configuration supports Ruby on Rails applications.<br>
51
- The executable is set to "bin/rails" by default.<br>
52
- The default executable parameters are "server -p 8080 -e production".
52
+ The default configuration if focused on Ruby on Rails applications.<br>
53
+
54
+ ### Configuration options
55
+ | Option | Default value | Description |
56
+ |-------------------|--------------------------------------------------------------------------------|---------------------------------------------------------------------|
57
+ | executable | "bin/rails" | The ruby file to run at execution of jar file |
58
+ | executable_params | ["server", "-e", "production", "-p", "8080"] | Command line parameters to be used for the ruby executable |
59
+ | excludes | ["tmp/cache", "tmp/pids", ...] (see generated template file for whole content) | The files and dirs of the project to exlude from the include option |
60
+ | includes | ["app", "bin", "config", ...] (see generated template file for whole content) | The files and dirs of the project to include in the jar file |
61
+ | jar_name | &lt; Name of project dir &gt;.jar | The name of the generated jar file |
62
+ | jruby_version | The current most recent jRuby version | The version of the jRuby runtime to use |
63
+
53
64
 
54
65
  ## Troubleshooting
55
66
  * Set DEBUG=true in environment to get additional runtime information
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) {
@@ -54,7 +57,7 @@ class JarMain {
54
57
  jarPath = jarPath.substring(1); // remove the leading slash
55
58
  }
56
59
 
57
- // extract the jarFile by executing jar -xf jarFileName
60
+ // extract the jarFile by unzipping it (not using the jar utility which may not be available)
58
61
  System.out.println("Extracting files from "+jarPath+" to "+ newFolder.getAbsolutePath());
59
62
  unzip(jarPath, newFolder.getAbsolutePath());
60
63
 
@@ -132,8 +135,10 @@ class JarMain {
132
135
  debug(" - " + arg);
133
136
  }
134
137
 
138
+ debug("jRuby set property 'user.dir' to '" + app_root + "'");
135
139
  System.setProperty("user.dir", app_root);
136
140
  // call the method org.jruby.Main.main
141
+ debug("Calling org.jruby.Main.main with: "+ mainArgs);
137
142
  mainMethod.invoke(null, (Object)mainArgs.toArray(new String[mainArgs.size()]));
138
143
  } catch (Exception e) {
139
144
  e.printStackTrace();
@@ -225,4 +230,18 @@ class JarMain {
225
230
  fw.write("BUNDLE_WITHOUT: test:development\n");
226
231
  fw.close();
227
232
  }
233
+
234
+ private static String jar_file_name() {
235
+ String jarFileName = "";
236
+
237
+ try {
238
+ ProtectionDomain protectionDomain = JarMain.class.getProtectionDomain();
239
+ CodeSource codeSource = protectionDomain.getCodeSource();
240
+ URL location = codeSource.getLocation();
241
+ jarFileName = new File(location.toURI()).getName();
242
+ } catch (Exception e) {
243
+ e.printStackTrace();
244
+ }
245
+ return jarFileName;
246
+ }
228
247
  }
@@ -13,13 +13,12 @@ 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
 
22
- ruby_version = copy_jruby_jars_to_staging(staging_dir) # Copy the jruby jars to the staging directory
21
+ ruby_minor_version = copy_jruby_jars_to_staging(staging_dir) # Copy the jruby jars to the staging directory
23
22
  exec_command "javac -nowarn -Xlint:deprecation -source 8 -target 8 -d #{staging_dir} #{__dir__}/JarMain.java" # Compile the Java files
24
23
 
25
24
  # Copy the application project to the staging directory
@@ -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_minor_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_minor_version [String] the corresponding ruby minor 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_minor_version)
107
+ gem_target_location = "#{staging_dir}/gems/jruby/#{ruby_minor_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,8 +200,7 @@ 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
- # @return [String] the ruby version of the jRuby jars
203
+ # @return [String] the minor ruby version of the jRuby jars with patch level set to 0
184
204
  def copy_jruby_jars_to_staging(staging_dir)
185
205
 
186
206
  # Ensure that jruby-jars gem is installed, otherwise install it. Accepts also bundler path in .bundle/config
@@ -204,10 +224,14 @@ module Jarbler
204
224
  raise "Could not determine Ruby version for jRuby #{config.jruby_version} in following output:\n#{lines}" unless match_result
205
225
  ruby_version = match_result[0].tr('()', '')
206
226
  debug "Corresponding Ruby version for jRuby (#{config.jruby_version}): #{ruby_version}"
207
- ruby_version
227
+ ruby_minor_version = ruby_version.split('.')[0..1].join('.') + '.0'
228
+ debug "Corresponding Ruby minor version for jRuby (#{config.jruby_version}): #{ruby_minor_version}"
229
+ ruby_minor_version
208
230
  end
209
231
 
210
- # Execute the command and return the output
232
+ # Execute the command in OS and return the output
233
+ # @param [String] command Command to execute
234
+ # @return [String] the output of the command
211
235
  def exec_command(command)
212
236
  lines = `#{command}`
213
237
  raise "Command \"#{command}\"failed with return code #{$?} and output:\n#{lines}" unless $?.success?
@@ -216,6 +240,9 @@ module Jarbler
216
240
  end
217
241
 
218
242
  # Copy file or directory with error handling
243
+ # @param [String] source Path to the source file or directory
244
+ # @param [String] destination Path to the destination file or directory
245
+ # @return [void]
219
246
  def file_utils_copy(source, destination)
220
247
  if File.exist?(source) && File.directory?(source)
221
248
  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.5"
5
+ VERSION_DATE = "2023-06-15"
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.5
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-06-15 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:
@@ -55,7 +55,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
55
55
  - !ruby/object:Gem::Version
56
56
  version: '0'
57
57
  requirements: []
58
- rubygems_version: 3.3.26
58
+ rubygems_version: 3.0.3.1
59
59
  signing_key:
60
60
  specification_version: 4
61
61
  summary: Pack a Ruby app into a Java jar file