jarbler 0.3.2 → 0.3.5

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: d57d186383ffc6bf5de8396b10fa81aa47947bedb96f36ef67d4cbecef2ca2fb
4
- data.tar.gz: 64c3888a99ec67bbf0e4ac0c3c85a5d2f8cd042a84403ad879a02476c8c62a80
3
+ metadata.gz: 2b0f184ae1d09ac0464ed7c607600571e77873ae91a1aa2c20578856cd2b8404
4
+ data.tar.gz: 0dce28c9d7e4856d5903da84f8ea4f5ec5f173931fe4fca6ec5e8e849bbcbc4b
5
5
  SHA512:
6
- metadata.gz: 4ef50f2616b885cca428943bcc6baf4d0db106da0e7620339981378ef2321ccd6b336c7c992a10531e670b6c63baa80d14f37512e8890b9136593047267adbcb
7
- data.tar.gz: f4b1644168cdc90c5314b65cf616b1d096bec65888de485b490744f68b9577867c9a3625f8dbc7e443c11c7b57ea125210ce45a159f3e8ad477f559d8610f910
6
+ metadata.gz: 7b4383469571b3ce72c7e97123f8a8a0b25834848970921ae84dd445f3ea9268fec77193b796dddd2444831d5854e477d13d912de9d962fea3bcdd74ecb9d56d
7
+ data.tar.gz: dfcfdd76de3397adabb0e8677c09dedc112486387addeca59f8b85b50b40f8d7230c337b61c191f2d2752eb1cf9514011905579818add6665cce66dc38db0b66
data/CHANGELOG.md CHANGED
@@ -1,5 +1,18 @@
1
1
  ## [Unreleased]
2
2
 
3
+ ## [0.3.5] - 2025-03-22
4
+
5
+ - new config attribute "config.compile_java_version" allows control of setting for "javac -source and -target" for AOT compilation
6
+ - fix typo with smart quotes in config.rb
7
+
8
+ ## [0.3.4] - 2025-03-07
9
+
10
+ - Warning if Ruby-specific environment variables (GEM_HOME etc.) are set which may cause malfunction of app in jar file
11
+ - Accept jar file locations with blanks in the path, especially for Windows
12
+ - Setting `compile_ruby_files=true` compiles only .rb file of the application, but does not compile the .rb files in Gems.<br/>
13
+ Compiling the Gems also remains an open task.
14
+ - Bugfix: Accept spaces in the path to the jar file, especially for Windows
15
+
3
16
  ## [0.3.1] - 2024-07-02
4
17
 
5
18
  - Use file .ruby-version to define the JRuby version for the jar file only if .ruby-version contains a valid jRuby version
data/README.md CHANGED
@@ -53,16 +53,17 @@ To create a template config file with information about all the supported config
53
53
  The default configuration is focused on Ruby on Rails applications.<br>
54
54
 
55
55
  ### Configuration options
56
- | Option | Default value | Description |
57
- |-------------------------|------------------------------------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------|
58
- | compile_ruby_files | false | Ahead of time compilation of all .rb files of application and Gem dependencies to .class files. Only store .class files in jar. Requires JRuby runtime. |
59
- | executable | "bin/rails" | The ruby start file to run at execution of jar file. File extension .class is used automatically if start file is .rb and AOT compilation is used. |
60
- | executable_params | ["server", "-e", "production", "-p", "8080"] | Command line parameters to be used for the ruby executable |
61
- | excludes_from_compile | [] | The files and dirs of the project to exclude from the compilation of .rb files. Paths specifies the location in the jar file (e.g. ["app_root/file.rb"] ) |
62
- | excludes | ["tmp/cache", "tmp/pids", ...] (see generated template file for whole content) | The files and dirs of the project to exclude from the include option |
63
- | includes | ["app", "bin", "config", ...] (see generated template file for whole content) | The files and dirs of the project to include in the jar file |
64
- | jar_name | &lt; Name of project dir &gt;.jar | The name of the generated jar file |
65
- | jruby_version | A valid JRuby version from file '.ruby-version' or the current most recent version of the Gem 'jruby-jars' | The version of the JRuby runtime to use |
56
+ | Option | Default value | Description |
57
+ |-------------------------|------------------------------------------------------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
58
+ | compile_java_version | none | Java version the compiled .class files should be compatible with. Controls the target and source version of the Java compiler if compile_ruby_files=true (javac -source and -target). E.g. "1.8" for Java 8. If not set then it generates the class file version according to your current Java version. |
59
+ | compile_ruby_files | false | Ahead of time compilation of all .rb files of the application to .class files. Only the .class files are stored in the jar file. The Gem dependencies are not compiled. Requires JRuby as Ruby environment at compile time. |
60
+ | executable | "bin/rails" | The ruby start file to run at execution of jar file. File extension .class is used automatically if start file is .rb and AOT compilation is used. |
61
+ | executable_params | ["server", "-e", "production", "-p", "8080"] | Command line parameters to be used for the ruby executable |
62
+ | excludes_from_compile | [] | The files and dirs of the project to exclude from the compilation of .rb files. Paths specifies the location in the jar file (e.g. ["app_root/file.rb"] ) |
63
+ | excludes | ["tmp/cache", "tmp/pids", ...] (see generated template file for whole content) | The files and dirs of the project to exclude from the include option |
64
+ | includes | ["app", "bin", "config", ...] (see generated template file for whole content) | The files and dirs of the project to include in the jar file |
65
+ | jar_name | &lt; Name of project dir &gt;.jar | The name of the generated jar file |
66
+ | jruby_version | A valid JRuby version from file '.ruby-version' or the current most recent version of the Gem 'jruby-jars' | The version of the JRuby runtime to use |
66
67
 
67
68
 
68
69
  ## Troubleshooting
@@ -10,6 +10,7 @@ import java.util.jar.JarFile;
10
10
  import java.util.jar.JarInputStream;
11
11
  import java.util.jar.JarOutputStream;
12
12
  import java.util.ArrayList;
13
+ import java.util.Arrays;
13
14
  import java.util.Properties;
14
15
  import java.util.zip.ZipEntry;
15
16
  import java.util.zip.ZipInputStream;
@@ -42,26 +43,28 @@ class JarMain {
42
43
  debug(" - " + arg);
43
44
  }
44
45
  }
46
+
45
47
  // create a new folder in temp directory
46
48
  File newFolder = new File(System.getProperty("java.io.tmpdir") + File.separator + UUID.randomUUID().toString());
47
49
  newFolder.mkdir();
50
+
48
51
  try {
49
- // Get the path of the jar file
50
- String jarPath = JarMain.class.getProtectionDomain().getCodeSource().getLocation().getPath();
51
-
52
- // remove the leading slash if path is a windows path
53
- String os = System.getProperty("os.name").toLowerCase();
54
- boolean isWindows = os.contains("windows");
55
- if (os.contains("windows") && jarPath.startsWith("/") && jarPath.indexOf(':') != -1) {
56
- jarPath = jarPath.substring(1); // remove the leading slash
57
- }
58
52
 
59
- // get the absolute path of the jar file, especially if it contains spaces in Windows
60
- String aboluteJarPath = new File(jarPath).getAbsolutePath();
53
+ // Ensure that environment does not inject external dependencies
54
+ checkEnvForToxicEntries();
55
+
56
+ // Get the path of the jar file with valid characters for spaces etc., especially for Windows
57
+ URL jarPathUrl = JarMain.class.getProtectionDomain().getCodeSource().getLocation();
58
+
59
+ // Convert the URL to a URI, then to a File
60
+ File jarFile = new File(jarPathUrl.toURI());
61
+
62
+ // Get the absolute path of the file
63
+ String jarPath = jarFile.getAbsolutePath();
61
64
 
62
65
  // extract the jarFile by unzipping it (not using the jar utility which may not be available)
63
- System.out.println("Extracting files from "+aboluteJarPath+" to "+ newFolder.getAbsolutePath());
64
- unzip(aboluteJarPath, newFolder.getAbsolutePath());
66
+ System.out.println("Extracting files from "+jarPath+" to "+ newFolder.getAbsolutePath());
67
+ unzip(jarPath, newFolder.getAbsolutePath());
65
68
 
66
69
  String app_root = newFolder.getAbsolutePath()+File.separator+"app_root";
67
70
 
@@ -87,8 +90,9 @@ class JarMain {
87
90
 
88
91
  Properties prop = new Properties();
89
92
  prop.load(new FileInputStream(newFolder.getAbsolutePath()+File.separator+"jarbler.properties"));
90
- executable = prop.getProperty("jarbler.executable");
91
- executable_params = prop.getProperty("jarbler.executable_params");
93
+ executable = prop.getProperty("jarbler.executable");
94
+ executable_params = prop.getProperty("jarbler.executable_params");
95
+ String gem_home_suffix = prop.getProperty("jarbler.gem_home_suffix");
92
96
 
93
97
  Boolean compile_ruby_files = Boolean.parseBoolean(prop.getProperty("jarbler.compile_ruby_files", "false"));
94
98
  if (compile_ruby_files) {
@@ -102,8 +106,11 @@ class JarMain {
102
106
  throw new RuntimeException("Property 'executable' definition missing in jarbler.properties");
103
107
  }
104
108
 
109
+ // single path to the gems directory
110
+ String gem_home = newFolder.getAbsolutePath()+File.separator+"gems";
111
+
105
112
  // create the bundle config file with the path of the gems
106
- create_bundle_config(app_root, newFolder.getAbsolutePath()+File.separator+"gems");
113
+ create_bundle_config(app_root, gem_home);
107
114
 
108
115
  // Load the Jar file
109
116
  URLClassLoader classLoader = new URLClassLoader(new URL[]{
@@ -112,7 +119,6 @@ class JarMain {
112
119
  //new URL("file:/" + jrubyCoreFile.getAbsolutePath()),
113
120
  //new URL("file:/" + jrubyStdlibFile.getAbsolutePath())
114
121
  });
115
-
116
122
  // Load the class
117
123
  Class<?> clazz = classLoader.loadClass("org.jruby.Main");
118
124
 
@@ -139,16 +145,24 @@ class JarMain {
139
145
  }
140
146
  }
141
147
 
148
+ debug("JRuby set property 'user.dir' to '" + app_root + "'");
149
+ System.setProperty("user.dir", app_root);
150
+
151
+ // GEM_HOME not explicitely set because this is done by Bundle.setup based on the .bundle/config file
152
+ // Setting GEM_HOME explicitely may cause problems with the JRuby runtime (Gem::GemNotFoundException: can't find gem bundler (= 2.6.3) with executable bundle)
153
+ //String full_gem_home = gem_home + File.separator + gem_home_suffix.replace("/", File.separator);
154
+ //debug("JRuby set property 'jruby.gem.home' to '" + full_gem_home + "'");
155
+ //System.setProperty("jruby.gem.home", full_gem_home);
156
+
142
157
  debug("JRuby program starts with the following arguments: ");
143
158
  for (String arg : mainArgs) {
144
159
  debug(" - " + arg);
145
160
  }
146
161
 
147
- debug("JRuby set property 'user.dir' to '" + app_root + "'");
148
- System.setProperty("user.dir", app_root);
149
162
  // call the method org.jruby.Main.main
150
163
  debug("Calling org.jruby.Main.main with: "+ mainArgs);
151
164
  mainMethod.invoke(null, (Object)mainArgs.toArray(new String[mainArgs.size()]));
165
+ // TODO: evaluate return value
152
166
  } catch (Exception e) {
153
167
  e.printStackTrace();
154
168
  } finally {
@@ -228,7 +242,7 @@ class JarMain {
228
242
 
229
243
  private static void debug(String msg) {
230
244
  if (System.getenv("DEBUG") != null) {
231
- System.out.println(msg);
245
+ System.err.println(msg);
232
246
  }
233
247
  }
234
248
 
@@ -269,4 +283,38 @@ class JarMain {
269
283
  }
270
284
  return jarFileName;
271
285
  }
286
+
287
+ /**
288
+ * Check environment for entries that may inluence execution of Ruby code.
289
+ * @param errorSummary The current error summary
290
+ */
291
+ private static void checkEnvForToxicEntries(){
292
+ StringBuilder errorSummary = new StringBuilder("");
293
+ String toxicEntries[] = {
294
+ "BUNDLE_BIN_PATH",
295
+ "BUNDLE_GEMFILE",
296
+ "BUNDLER_SETUP",
297
+ "BUNDLER_VERSION",
298
+ "GEM_HOME",
299
+ "GEM_PATH",
300
+ "RUBYLIB",
301
+ "RUBYOPT",
302
+ "RUBYPATH",
303
+ "RUBYSHELL"
304
+ };
305
+
306
+ Arrays.stream(toxicEntries).forEach(entry -> {
307
+ String envVal = System.getenv(entry);
308
+ if (envVal != null) {
309
+ errorSummary.append("Found environment variable '"+entry+"' with value '"+envVal+"'\n");
310
+ debug("Possibly toxic environment variable found: '"+entry+"'! Remove it from environment before execution of jar file if it causes errors.");
311
+ }
312
+ });
313
+
314
+ if (!errorSummary.toString().isEmpty()){
315
+ System.err.println("The follwing environment variables may influence the execution of the packaged Ruby code.");
316
+ System.err.println("Please remove this environment entries before the execution of the jar file if they cause errors.");
317
+ System.err.println(errorSummary);
318
+ }
319
+ }
272
320
  }
@@ -4,6 +4,7 @@ require 'bundler'
4
4
  require 'find'
5
5
  require 'fileutils'
6
6
  require 'yaml'
7
+ require 'open3'
7
8
 
8
9
  module Jarbler
9
10
  class Builder
@@ -18,8 +19,12 @@ module Jarbler
18
19
  app_root = Dir.pwd
19
20
  debug "Project dir: #{app_root}"
20
21
 
22
+ source_and_target = if config.compile_java_version
23
+ "-source #{config.compile_java_version} -target #{config.compile_java_version}"
24
+ end
25
+
21
26
  ruby_minor_version = copy_jruby_jars_to_staging(staging_dir) # Copy the jruby jars to the staging directory
22
- exec_command "javac -nowarn -Xlint:deprecation -source 8 -target 8 -d #{staging_dir} #{__dir__}/JarMain.java" # Compile the Java files
27
+ exec_command "javac -nowarn -Xlint:deprecation #{source_and_target} -d #{staging_dir} #{__dir__}/JarMain.java" # Compile the Java files
23
28
 
24
29
  # Copy the application project to the staging directory
25
30
  FileUtils.mkdir_p("#{staging_dir}/app_root")
@@ -50,6 +55,7 @@ module Jarbler
50
55
  end
51
56
  file.write("jarbler.executable_params=#{java_executable_params.strip}\n")
52
57
  file.write("jarbler.compile_ruby_files=#{config.compile_ruby_files}\n")
58
+ file.write("jarbler.gem_home_suffix=jruby/#{ruby_minor_version}\n") # Extension after BUNDLE_PATH for local Gems
53
59
  end
54
60
 
55
61
  # remove files and directories from excludes, if they exist (after copying the rails project and the gems)
@@ -86,30 +92,20 @@ module Jarbler
86
92
 
87
93
  private
88
94
 
89
-
90
- # Check if there is an additional local bundle path in .bundle/config
91
- # @param rails_root [String] the rails root directory
92
- # @return [String] the local bundle path or nil if not configured
93
- def bundle_config_bundle_path(rails_root)
94
- bundle_path = nil # default
95
- if File.exist?("#{rails_root}/.bundle/config")
96
- bundle_config = YAML.load_file("#{rails_root}/.bundle/config")
97
- if bundle_config && bundle_config['BUNDLE_PATH']
98
- bundle_path = "#{rails_root}/#{bundle_config['BUNDLE_PATH']}"
99
- debug "Local Gem path configured in #{rails_root}/.bundle/config: #{bundle_path}"
100
- end
101
- end
102
- bundle_path
103
- end
104
-
105
95
  # Copy the needed Gems to the staging directory
106
96
  # @param staging_dir [String] the staging directory
107
97
  # @param ruby_minor_version [String] the corresponding ruby minor version of the jruby jars version
108
98
  # @return [void]
109
99
  def copy_needed_gems_to_staging(staging_dir, ruby_minor_version)
110
100
  gem_target_location = "#{staging_dir}/gems/jruby/#{ruby_minor_version}"
101
+ FileUtils.mkdir_p("#{gem_target_location}/bin")
102
+ FileUtils.mkdir_p("#{gem_target_location}/build_info")
103
+ FileUtils.mkdir_p("#{gem_target_location}/cache")
104
+ FileUtils.mkdir_p("#{gem_target_location}/doc")
105
+ FileUtils.mkdir_p("#{gem_target_location}/extensions")
111
106
  FileUtils.mkdir_p("#{gem_target_location}/gems")
112
107
  FileUtils.mkdir_p("#{gem_target_location}/specifications")
108
+ FileUtils.mkdir_p("#{gem_target_location}/bundler/bin")
113
109
  FileUtils.mkdir_p("#{gem_target_location}/bundler/gems")
114
110
 
115
111
  needed_gems = gem_dependencies # get the full names of the dependencies
@@ -123,21 +119,34 @@ module Jarbler
123
119
  if spec.source.is_a?(Bundler::Source::Git)
124
120
  # Copy the Gem from bundler/gems including the gemspec
125
121
  file_utils_copy(spec.gem_dir, "#{gem_target_location}/bundler/gems")
122
+ spec.executables.each do |executable|
123
+ file_utils_copy("#{spec.bin_dir}/#{executable}", "#{gem_target_location}/bundler/bin")
124
+ end
126
125
  else # Gem is from rubygems
126
+ # TODO: Gemfile could request a different version of default gem compared to the one jruby jars
127
+ # Should the default gems are also copied to the staging directory?
127
128
  unless spec.default_gem? # Do not copy default gems, because they are already included in the jruby jars standard library
128
129
  # copy the Gem and gemspec separately
129
130
  file_utils_copy(spec.gem_dir, "#{gem_target_location}/gems")
130
- file_utils_copy("#{spec.gem_dir}/../../specifications/#{needed_gem[:full_name]}.gemspec", "#{gem_target_location}/specifications")
131
+ # spec.loaded_from contains the path to the gemspec file including the path prefix "default/" for default gems
132
+ file_utils_copy(spec.loaded_from, "#{gem_target_location}/specifications")
133
+ spec.executables.each do |executable|
134
+ file_utils_copy("#{spec.bin_dir}/#{executable}", "#{gem_target_location}/bin")
135
+ end
131
136
  end
132
137
  end
133
138
  end
139
+ rescue Exception => e
140
+ debug("Builder.copy_needed_gems_to_staging: Failed with staging dir = '#{staging_dir}' and ruby minor version = #{ruby_minor_version} with #{e.class}\n#{e.message}")
141
+ raise
134
142
  end
135
143
 
136
144
  # Read the default/production dependencies from Gemfile.lock and Gemfile
137
145
  # @return [Array] Array with Hashes containing: name, version, full_name
138
146
  def gem_dependencies
139
147
  needed_gems = []
140
- lockfile_specs = Bundler::LockfileParser.new(Bundler.read_file(Bundler.default_lockfile)).specs
148
+ lockfile_parser = Bundler::LockfileParser.new(Bundler.read_file(Bundler.default_lockfile))
149
+ lockfile_specs = lockfile_parser.specs
141
150
 
142
151
  Bundler.setup # Load Gems specified in Gemfile, ensure that Gem path also includes the Gems loaded into bundler dir
143
152
  # filter Gems needed for production
@@ -156,10 +165,18 @@ module Jarbler
156
165
  debug "Direct Gem dependency: #{lockfile_spec.full_name}"
157
166
  add_indirect_dependencies(lockfile_specs, lockfile_spec, needed_gems)
158
167
  else
159
- debug "Gem #{gemfile_spec.name} not found in Gemfile.lock"
168
+ if gemfile_spec.name == 'bundler'
169
+ debug "Gem bundler found in Gemfile.lock but not in specs, use version #{Bundler::VERSION}"
170
+ needed_gems << { full_name: "bundler-#{lockfile_parser.bundler_version}", name: 'bundler', version: lockfile_parser.bundler_version }
171
+ else
172
+ debug "Gem #{gemfile_spec.name} not found in specs: in Gemfile.lock"
173
+ end
160
174
  end
161
175
  end
162
- needed_gems.uniq.sort{|a,b| a[:full_name] <=> b[:full_name]}
176
+ needed_gems.uniq.sort{|a,b| a[:full_name] <=> b[:full_name]} # full_name also contains version
177
+ rescue Exception => e
178
+ debug("Builder.gem_dependencies: Failed with #{e.class}\n#{e.message}")
179
+ raise
163
180
  end
164
181
 
165
182
  # recurively find all indirect dependencies
@@ -180,13 +197,16 @@ module Jarbler
180
197
  debug "Gem #{lockfile_spec_dep.name} not found in Gemfile.lock"
181
198
  end
182
199
  end
200
+ rescue Exception => e
201
+ debug("Builder.add_indirect_dependencies: Failed with #{e.class}\n#{e.message}")
202
+ raise
183
203
  end
184
204
 
185
205
  # Output debug message if DEBUG environment variable is set
186
206
  # @param [String] msg Message to output
187
207
  # @return [void]
188
208
  def debug(msg)
189
- puts msg if ENV['DEBUG']
209
+ puts "#{Time.now.strftime('%Y-%m-%d %H:%M:%S')} #{msg}" if ENV['DEBUG']
190
210
  end
191
211
 
192
212
  # Get the config object
@@ -201,6 +221,9 @@ module Jarbler
201
221
  debug ""
202
222
  end
203
223
  @config
224
+ rescue Exception => e
225
+ debug("Builder.config: Failed with #{e.class}\n#{e.message}")
226
+ raise
204
227
  end
205
228
 
206
229
  # Copy the jruby-jars to the staging directory
@@ -208,12 +231,26 @@ module Jarbler
208
231
  # @return [String] the minor ruby version of the JRuby jars with patch level set to 0
209
232
  def copy_jruby_jars_to_staging(staging_dir)
210
233
 
234
+ debug "Copying JRuby Jars to staging dir: #{staging_dir}"
211
235
  # Ensure that jruby-jars gem is installed, otherwise install it. Accepts also bundler path in .bundle/config
212
- installer = Gem::DependencyInstaller.new
213
- installed = installer.install('jruby-jars', config.jruby_version)
236
+ installed = nil # ensure that installed is defined outside of the block
237
+ tries = 5
238
+ tries.times do |try|
239
+ begin
240
+ installer = Gem::DependencyInstaller.new
241
+ installed = installer.install('jruby-jars', config.jruby_version)
242
+ break # escape loop if successful
243
+ rescue Exception, RuntimeError => e
244
+ debug "Builder.copy_jruby_jars_to_staging: Failed to install jruby-jars #{try}. try with #{e.class}\n#{e.message}"
245
+ raise if try == tries - 1 # last try not successful
246
+ sleeptime = 5
247
+ debug "Builder.copy_jruby_jars_to_staging: Waiting #{sleeptime} seconds to prevent from Gem::RemoteFetcher::FetchError: IOError: closed stream"
248
+ sleep sleeptime # wait x seconds before next try
249
+ end
250
+ end
214
251
  raise "jruby-jars gem not installed in version #{config.jruby_version}" if installed.empty?
215
252
 
216
- jruby_jars_location = installed[0]&.full_gem_path
253
+ jruby_jars_location = installed[0]&.full_gem_path # need to be the first installed Gem
217
254
  debug "JRuby jars installed at: #{jruby_jars_location}"
218
255
 
219
256
  # Get the location of the jruby-jars gem
@@ -232,16 +269,24 @@ module Jarbler
232
269
  ruby_minor_version = ruby_version.split('.')[0..1].join('.') + '.0'
233
270
  debug "Corresponding Ruby minor version for JRuby (#{config.jruby_version}): #{ruby_minor_version}"
234
271
  ruby_minor_version
272
+ rescue Exception => e
273
+ debug "Builder.copy_jruby_jars_to_staging: Failed to copy JRuby jars to staging dir '#{jruby_jars_location}' with #{e.class}\n#{e.message}"
274
+ debug "Stack trace of exception:\n#{e.backtrace.join("\n")}"
275
+ raise
235
276
  end
236
277
 
237
278
  # Execute the command in OS and return the output
238
279
  # @param [String] command Command to execute
239
280
  # @return [String] the output of the command
240
281
  def exec_command(command)
241
- lines = `#{command}`
242
- raise "Command \"#{command}\"failed with return code #{$?} and output:\n#{lines}" unless $?.success?
243
- debug "Command \"#{command}\" executed successfully with following output:\n#{lines}"
244
- lines
282
+ debug("Execute by Open3.capture3: #{command}")
283
+ stdout, stderr, status = Open3.capture3(command)
284
+ debug "Command \"#{command}\" executed with return code #{status}!\nstdout:\n#{stdout}\n\nstderr:\n#{stderr}\n"
285
+ raise "Command \"#{command}\" failed with return code #{status}!\nstdout:\n#{stdout}\n\nstderr:\n#{stderr}\n" unless status.success?
286
+ "stdout:\n#{stdout}\nstderr:\n#{stderr}\n"
287
+ rescue Exception => e
288
+ debug "Builder.exec_command: Failed to execute command '#{command}' with #{e.class}\n#{e.message}"
289
+ raise
245
290
  end
246
291
 
247
292
  # Copy file or directory with error handling
@@ -254,8 +299,8 @@ module Jarbler
254
299
  else
255
300
  FileUtils.cp(source, destination)
256
301
  end
257
- rescue Exception
258
- puts "Error copying #{source} to #{destination}"
302
+ rescue Exception => e
303
+ debug "Builder.file_utils_copy: Failed to copy '#{source}' to '#{destination}' with #{e.class}\n#{e.message}"
259
304
  raise
260
305
  end
261
306
 
@@ -267,9 +312,12 @@ module Jarbler
267
312
  # Inform if used JRuby version is different from the intended runtime JRuby version
268
313
  if JRUBY_VERSION != config.jruby_version
269
314
  puts "Compiling .rb files to .class is done with JRuby version #{JRUBY_VERSION}, but intended runtime JRuby version for jar file is #{config.jruby_version}"
315
+ puts "Mismatch between the JRuby versions used for compile and runtime is not supported by JRuby and may cause sudden errors"
316
+ raise "JRuby version mismatch: #{JRUBY_VERSION} != #{config.jruby_version}"
270
317
  end
271
318
 
272
- ruby_files = Find.find('.').select { |f| f =~ /\.rb$/ } # find all Ruby files in the current directory
319
+ # Compile all .rb files in the current directory tree, but not in the gems directory
320
+ ruby_files = Find.find('.').select { |f| f =~ /\.rb$/ && !f.include?("#{File::SEPARATOR}gems#{File::SEPARATOR}") } # find all Ruby files in the current directory
273
321
 
274
322
  # Exclude named files or directories from compiling
275
323
  config.excludes_from_compile.each do |exclude|
@@ -291,6 +339,9 @@ module Jarbler
291
339
  puts "'#{ruby_file}' is not compiled and will be included in the jar file as original Ruby file"
292
340
  end
293
341
  end
342
+ rescue Exception => e
343
+ puts "Builder.compile_ruby_files: Failed to compile Ruby files with #{e.class}\n#{e.message}"
344
+ raise
294
345
  end
295
346
  end
296
347
  end
@@ -3,7 +3,7 @@ require 'json'
3
3
 
4
4
  module Jarbler
5
5
  class Config
6
- attr_accessor :jar_name, :includes, :excludes, :jruby_version, :executable, :executable_params, :compile_ruby_files, :excludes_from_compile
6
+ attr_accessor :jar_name, :includes, :excludes, :jruby_version, :executable, :executable_params, :compile_ruby_files, :excludes_from_compile, :compile_java_version
7
7
 
8
8
  CONFIG_FILE = 'config/jarble.rb'
9
9
  # create instance of Config class with defaults or from config file
@@ -31,9 +31,10 @@ module Jarbler
31
31
  puts "No configuration file found at #{File.join(Dir.pwd, CONFIG_FILE)}. Using default values."
32
32
  end
33
33
  puts "Used configuration values are:"
34
+ puts " compile_java_version: #{config.compile_java_version}" if config.compile_ruby_files
34
35
  puts " compile_ruby_files: #{config.compile_ruby_files}"
35
36
  puts " excludes: #{config.excludes}"
36
- puts " excludes_from_compile: #{config.excludes_from_compile}"
37
+ puts " excludes_from_compile: #{config.excludes_from_compile}" if config.compile_ruby_files
37
38
  puts " executable: #{config.executable}"
38
39
  puts " executable_params: #{config.executable_params}"
39
40
  puts " includes: #{config.includes}"
@@ -45,6 +46,7 @@ module Jarbler
45
46
 
46
47
  def initialize
47
48
  @compile_ruby_files = false
49
+ @compile_java_version = nil # not specified by default
48
50
  @excludes = %w(tmp/cache tmp/pids tmp/sockets vendor/bundle vendor/cache vendor/ruby)
49
51
  @excludes_from_compile = []
50
52
  @executable = 'bin/rails'
@@ -86,6 +88,11 @@ module Jarbler
86
88
  # the original ruby files are not included in the jar file, so source code is not visible
87
89
  # config.compile_ruby_files = #{compile_ruby_files}
88
90
 
91
+ # Java version the compiled .class files should be compatible with
92
+ # controls the target and source version of the Java compiler (javac -source and -target)
93
+ # if not set then it generates the class file version according to your current Java version
94
+ # config.compile_java_version = '1.8'
95
+
89
96
  # Directories or files to exclude from the compilation if compile_ruby_files = true
90
97
  # The paths map to the final location of files or dirs in the jar file, e.g. config.excludes_from_compile = ['gems', 'app_root/app/models']
91
98
  # config.excludes_from_compile = #{excludes_from_compile}
@@ -143,12 +150,6 @@ module Jarbler
143
150
  @jruby_version = response&.first&.first&.first&.version&.to_s
144
151
  raise "Unable to determine the latest available version of jruby-jars gem!\nResponse = #{response.inspect}" unless @jruby_version
145
152
 
146
- #command = "gem search --remote jruby-jars"
147
- #lines = `#{command}`
148
- #raise "Command \"#{command}\" failed with return code #{$?} and output:\n#{lines}" unless $?.success?
149
- #jruby_jars_line = lines.match(/^jruby-jars \((.*)\)/)
150
- #raise "No jruby-jars gem found in rubygems.org!" unless jruby_jars_line
151
- #self.jruby_version = /\((.*?)\)/.match(jruby_jars_line.to_s)[1]
152
153
  debug "Jarbler::Config.define_jruby_version: JRuby version from latest jruby-jars gem: #{jruby_version}"
153
154
  end
154
155
  end
@@ -159,7 +160,7 @@ module Jarbler
159
160
 
160
161
  # Avoid exception if using depprecated config attribute include_gems_to_compile
161
162
  def include_gems_to_compile=(_value)
162
- puts "Configuration attribute 'include_gems_to_compile' is deprecated. Use 'excludes_from_compile = [\”gems\”]' instead."
163
+ puts "Configuration attribute 'include_gems_to_compile' is deprecated. Use 'excludes_from_compile = [\"gems\"]' instead."
163
164
  end
164
165
 
165
166
  def validate_values
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Jarbler
4
- VERSION = "0.3.2"
5
- VERSION_DATE = "2025-03-01"
4
+ VERSION = "0.3.5"
5
+ VERSION_DATE = "2025-03-22"
6
6
  end
data/log/.keep ADDED
File without changes
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: jarbler
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.2
4
+ version: 0.3.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: 2025-03-01 00:00:00.000000000 Z
11
+ date: 2025-03-22 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: Pack a Ruby app combined with JRuby runtime and all its Gem dependencies
14
14
  into a jar file to simply run the app on any Java platform by '> java -jar file.jar'
@@ -34,6 +34,7 @@ files:
34
34
  - lib/jarbler/builder.rb
35
35
  - lib/jarbler/config.rb
36
36
  - lib/jarbler/version.rb
37
+ - log/.keep
37
38
  - sig/jarbler.rbs
38
39
  homepage: https://github.com/rammpeter/jarbler
39
40
  licenses: