ruby2jar 0.1

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.
data/README ADDED
@@ -0,0 +1,48 @@
1
+ = Ruby2Jar - build JAR from Ruby script
2
+
3
+ Ruby2Jar build JAR from Ruby script. It copy gems, compile sources and
4
+ package JAR. It is a easy way to distribute your JRuby application or to
5
+ create Applet or Java Web Start.
6
+
7
+ You must have Java SDK to use JAR builder. Also you should run it from JRuby
8
+ for correct platform in gems.
9
+
10
+ If program containt Java files it must be in ext/ dir. Source Java files
11
+ without class files will be compiled.
12
+
13
+ == Installation
14
+ Use Gem to download and install Ruby2Jar.
15
+
16
+ gem install ruby2jar
17
+
18
+ == Usage
19
+ Add to your Rakefile:
20
+
21
+ require "ruby2jar"
22
+
23
+ PKG_NAME = "program"
24
+ PKG_VERSION = "0.1"
25
+
26
+ Ruby2Jar::Rake::JarTask.new do |jar|
27
+ jar.files = FileList["lib/**/*", "bin/*"]
28
+ jar.main = "bin/program"
29
+ jar.name = PKG_NAME
30
+ jar.version = PKG_VERSION
31
+ jar.add_dependency "rspec"
32
+ end
33
+
34
+ == Limitation
35
+ In current JRuby version (1.1.2) you can't use Ruby file system functions
36
+ and +__FILE__+ constant in JAR. So didn't use <tt>Dir.glob</tt> to require
37
+ all files in dir or somethink like this.
38
+
39
+ == Gem config
40
+ Gem can contain building config <tt>java.yaml</tt> in gem root. Builder will
41
+ find list of exclude file patterns in <tt>jar.exclude</tt> config node.
42
+
43
+ == License
44
+ Ruby2Jar is licensed under the GNU General Public License version 3.
45
+ You can read it in LICENSE file or in http://www.gnu.org/licenses/gpl.html .
46
+
47
+ == Author
48
+ Andrey "A.I." Sitnik <andrey@sitnik.ru>
@@ -0,0 +1,83 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+ require "rake/rdoctask"
4
+ require 'spec/rake/spectask'
5
+ require 'rake/gempackagetask'
6
+
7
+ require File.join(File.dirname(__FILE__), "lib", "ruby2jar")
8
+
9
+ ##############################################################################
10
+ # Tests
11
+ ##############################################################################
12
+
13
+ desc "Run all specs"
14
+ Spec::Rake::SpecTask.new('specs') do |t|
15
+ t.spec_opts = ["--format", "specdoc", "--colour"]
16
+ t.spec_files = Dir['spec/**/*_spec.rb'].sort
17
+ end
18
+
19
+ desc "Run a specific spec with TASK=xxxx"
20
+ Spec::Rake::SpecTask.new('spec') do |t|
21
+ t.spec_opts = ["--format", "specdoc", "--colour"]
22
+ t.libs = ['lib']
23
+ t.spec_files = ["spec/**/#{ENV['TASK']}_spec.rb"]
24
+ end
25
+
26
+ desc "Run all specs output html"
27
+ Spec::Rake::SpecTask.new('specs_html') do |t|
28
+ t.spec_opts = ["--format", "html"]
29
+ t.libs = ['lib']
30
+ t.spec_files = Dir['spec/**/*_spec.rb'].sort
31
+ end
32
+
33
+ desc "RCov"
34
+ Spec::Rake::SpecTask.new('rcov') do |t|
35
+ t.spec_opts = ["--format", "specdoc", "--colour"]
36
+ t.spec_files = Dir['spec/**/*_spec.rb'].sort
37
+ t.libs = ['lib']
38
+ t.rcov = true
39
+ end
40
+
41
+ ##############################################################################
42
+ # Documentation and distribution
43
+ ##############################################################################
44
+
45
+ Rake::RDocTask.new do |rdoc|
46
+ rdoc.main = "README"
47
+ rdoc.rdoc_files.include("README", "LICENSE", "lib/**/*.rb")
48
+ rdoc.title = "Ruby2Jar docs"
49
+ rdoc.rdoc_dir = "doc"
50
+ rdoc.options << "--all"
51
+ end
52
+
53
+ spec = Gem::Specification.new do |s|
54
+ s.platform = Gem::Platform::RUBY
55
+ s.name = "ruby2jar"
56
+ s.version = "0.1"
57
+ s.summary = "Build JAR from Ruby script."
58
+ s.description = <<-EOF
59
+ Ruby2Jar build JAR from Ruby script. It copy gems, compile sources and
60
+ package JAR. It is a easy way to distribute your JRuby application or to
61
+ create Applet or Java Web Start.
62
+ EOF
63
+
64
+ s.files = FileList[
65
+ "lib/**/*",
66
+ "spec/**/*",
67
+ "LICENSE",
68
+ "TODO",
69
+ "Rakefile",
70
+ "README"]
71
+ s.require_path = 'lib'
72
+
73
+ s.add_dependency 'rake'
74
+
75
+ s.author = 'Andrey "A.I." Sitnik'
76
+ s.email = "andrey@sitnik.ru"
77
+ s.homepage = "http://ruby2jar.rubyforge.org/"
78
+ s.rubyforge_project = "ruby2jar"
79
+ end
80
+
81
+ Rake::GemPackageTask.new(spec) do |pkg|
82
+ pkg.gem_spec = spec
83
+ end
data/TODO ADDED
@@ -0,0 +1,2 @@
1
+ * Gem list loader from gem task in Rakefile, gem spec file and tracing appliation
2
+ * Create JAR from gem
@@ -0,0 +1,31 @@
1
+ =begin
2
+ Load all neccessary classes.
3
+
4
+ Copyright (C) 2008 Andrey "A.I." Sitnik <andrey@sitnik.ru>
5
+
6
+ This program is free software: you can redistribute it and/or modify
7
+ it under the terms of the GNU General Public License as published by
8
+ the Free Software Foundation, either version 3 of the License, or
9
+ (at your option) any later version.
10
+
11
+ This program is distributed in the hope that it will be useful,
12
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
13
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
+ GNU General Public License for more details.
15
+
16
+ You should have received a copy of the GNU General Public License
17
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
18
+ =end
19
+
20
+ $LOAD_PATH.unshift File.expand_path(File.dirname(__FILE__)) unless
21
+ $LOAD_PATH.include?(File.dirname(__FILE__)) ||
22
+ $LOAD_PATH.include?(File.expand_path(File.dirname(__FILE__)))
23
+
24
+ require "ruby2jar/builder"
25
+
26
+ module Ruby2Jar
27
+ autoload :Listener, "ruby2jar/listener"
28
+ autoload :Console, "ruby2jar/console"
29
+ autoload :Error, "ruby2jar/error"
30
+ autoload :JarTask, "ruby2jar/jartask"
31
+ end
@@ -0,0 +1,436 @@
1
+ =begin
2
+ Build JAR from Ruby script.
3
+
4
+ Copyright (C) 2008 Andrey "A.I." Sitnik <andrey@sitnik.ru>
5
+
6
+ This program is free software: you can redistribute it and/or modify
7
+ it under the terms of the GNU General Public License as published by
8
+ the Free Software Foundation, either version 3 of the License, or
9
+ (at your option) any later version.
10
+
11
+ This program is distributed in the hope that it will be useful,
12
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
13
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
+ GNU General Public License for more details.
15
+
16
+ You should have received a copy of the GNU General Public License
17
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
18
+ =end
19
+
20
+ require "tmpdir"
21
+ require "tempfile"
22
+ require "yaml"
23
+ require "fileutils"
24
+
25
+ require "rubygems"
26
+ require "rake"
27
+
28
+ module Ruby2Jar
29
+ # Ruby2Jar build JAR from Ruby script. It copy gems, compile sources and
30
+ # package JAR. It is a easy way to distribute your JRuby application or to
31
+ # create Applet or Java Web Start.
32
+ #
33
+ # == Examples
34
+ # === Build from Rake task (best production way)
35
+ #
36
+ # require "ruby2jar"
37
+ #
38
+ # PKG_NAME = "program"
39
+ # PKG_VERSION = "0.1"
40
+ #
41
+ # Ruby2Jar::Rake::JarTask.new do |jar|
42
+ # jar.files = FileList["lib/**/*", "bin/*"]
43
+ # jar.main = "bin/program"
44
+ # jar.name = PKG_NAME
45
+ # jar.version = PKG_VERSION
46
+ # jar.add_dependency "rspec"
47
+ # end
48
+ #
49
+ # === Build with console output
50
+ #
51
+ # require "ruby2jar"
52
+ #
53
+ # builder = Ruby2Jar::Builder.new
54
+ # console = Ruby2Jar::Console.new(builder) # Add console error output
55
+ # builder.path = "/path/to/ruby/program/" # Set program to build
56
+ # builder.files = Rake::FileList["/lib/**/*"] # Select files
57
+ # builder.add_dependency "actionsupport" # Add gems
58
+ # builder.add_dependency "rspec", ">=1.0.0" # Add gem with special version
59
+ # builde.build # Start building
60
+ #
61
+ # == Extension
62
+ # You can add some action in building work. For example, to show warning
63
+ # dialogs or to create special manifest file. Just add new Proc or Method
64
+ # object to "before_*" arrays with neccessary building step.
65
+ #
66
+ # You can also extend Ruby2Jar::Listener to create extension, which
67
+ # automatically connect all function to builder.
68
+ #
69
+ # === Example
70
+ #
71
+ # require "ruby2jar"
72
+ #
73
+ # builder = Ruby2Jar::Builder.new
74
+ # builder.path = "/path/to/ruby/program/"
75
+ # builder.add_dependency "rspec"
76
+ #
77
+ # builder.before_start << lambda { # Add function, which will be
78
+ # puts "Jar building is start" # call before builder start and
79
+ # } # set system variables
80
+ #
81
+ # builder.before_finish << lambda { # Function, which will be call
82
+ # puts "Jar building is finish" # before builder finish it work
83
+ # } # and delete temporal files
84
+ #
85
+ class Builder
86
+ # Script or directory to build JAR
87
+ attr_accessor :path
88
+
89
+ # List of files to be included in the JAR.
90
+ attr_accessor :files
91
+
92
+ # Path to main script, which will be run whtn you execute JAR.
93
+ # If in +path+ you set file, main script will be equal +path+.
94
+ attr_accessor :main
95
+
96
+ # Does builder must create Manifest file in JAR with +main+ script, which
97
+ # will be start on JAR executing (default if true).
98
+ attr_accessor :create_manifest
99
+
100
+ # Custom content of Manifest file in JAR as hash. If parameters will be not
101
+ # set, builder add Manifest-Version and Main-Class if +main+ exist.
102
+ attr_accessor :manifest
103
+
104
+ # Path to result JAR (default is +path+/pkg/{last dirname in +path+}.jar).
105
+ attr_accessor :jar
106
+
107
+ # Does builder must copy JRuby to JAR (default if true). With JRuby
108
+ # resulting JAR can be started on any Java Runtime, but file will be has
109
+ # bigger size.
110
+ attr_accessor :include_jruby
111
+
112
+ # Path to JRuby JAR (default is $JRUBY_HOME/lib/jruby/jar). Used only
113
+ # if +include_jruby+ is true.
114
+ attr_accessor :jruby
115
+
116
+ # Arguments for Java compiler
117
+ attr_accessor :javac_args
118
+
119
+ # Path in script, which will be added to <tt>$LOAD_PATH</tt> in init script
120
+ # (default is root and lib dir of application)
121
+ attr_accessor :require_paths
122
+
123
+ # Create builder instance
124
+ def initialize
125
+ @path = Dir.pwd
126
+ @create_manifest = false
127
+ @manifest = {"Manifest-Version" => "1.0"}
128
+ @include_jruby = true
129
+ @target = "1.6"
130
+ @require_paths = ["lib", ""]
131
+ @javac_args = ""
132
+ @gems_index = Gem.source_index
133
+
134
+ @before_start = []
135
+ @before_find_gems = []
136
+ @before_copy = []
137
+ @before_create_init = []
138
+ @before_compile = []
139
+ @before_package = []
140
+ @before_finish = []
141
+ @on_error = []
142
+
143
+ @gems = []
144
+ @configs = {}
145
+ end
146
+
147
+ # Add a dependency gem
148
+ def add_dependency(gem, *requirements)
149
+ @gems << [gem, requirements]
150
+ end
151
+
152
+ # Start building JAR. You must set +path+ before call it.
153
+ def build
154
+ @stop = false
155
+ %w{start copy create_init compile package}.each do |step|
156
+ method("before_#{step}").call.each do |proc|
157
+ proc.call
158
+ end
159
+ if @stop
160
+ break
161
+ end
162
+ method(step).call
163
+ end
164
+ rescue => error
165
+ @error_rescued = false
166
+ on_error.each do |proc|
167
+ @error_rescued |= proc.call error
168
+ end
169
+ if not @error_rescued
170
+ raise error
171
+ end
172
+ ensure
173
+ begin
174
+ before_finish.each do |proc|
175
+ proc.call
176
+ end
177
+ ensure
178
+ finish
179
+ end
180
+ end
181
+
182
+ attr_accessor :before_start
183
+ attr_accessor :before_copy
184
+ attr_accessor :before_create_init
185
+ attr_accessor :before_compile
186
+ attr_accessor :before_package
187
+ attr_accessor :before_finish
188
+ attr_accessor :on_error
189
+
190
+ # Path to work dir, which be used to copy all neccessary files.
191
+ # It will be set automatically and has public access only for extensions.
192
+ attr_accessor :build_dir
193
+
194
+ # Gems, which using in program. Use +add_dependency+ to add gem.
195
+ attr_accessor :gems
196
+
197
+ # Gem's configs with building information, which was loaded from
198
+ # <tt>GEM_DIR/java.yaml</tt>. It will has information after +copy+ step.
199
+ attr_accessor :configs
200
+
201
+ # Paths to add to <tt>$LOAD_PATH</tt> in init script
202
+ attr_accessor :init_require_paths
203
+
204
+ # Gem's source index. It available as variable for testing and hacking.
205
+ attr_accessor :gems_index
206
+
207
+ # Gems, which is added to JAR. Contain @gems and they dependencies.
208
+ attr_accessor :loaded_gems
209
+
210
+ # Stop JAR building and delete temporal files. Must be runned from extension
211
+ # on error or when building is not necessary yet.
212
+ def stop
213
+ @stop = true
214
+ end
215
+
216
+ protected
217
+
218
+ # Check for errors and create temporal directory
219
+ def start
220
+ raise Error, "You didn't set path to source dir or file." if @path.nil?
221
+ raise Error, "Source path is already exist." if not File.exist? @path
222
+
223
+ @path = File.expand_path(@path)
224
+ if File.directory? @path
225
+ Dir.chdir(@path) do
226
+ @files = Rake::FileList["**/*"] if @files.nil?
227
+ @files.map! { |i| File.expand_path(i) }
228
+ end
229
+ end
230
+ if @jar.nil?
231
+ if File.directory? @path
232
+ @jar = File.join(@path, "pkg", "#{@path.split('/').last}.jar")
233
+ else
234
+ @jar = File.join(File.dirname(@path),
235
+ "#{File.basename(@path, File.extname(@path))}.jar")
236
+ end
237
+ end
238
+ @jar = File.expand_path(@jar)
239
+
240
+ if File.exist? @jar
241
+ raise Error, "File #{@jar} already exist. Delete it or change jar name"
242
+ end
243
+
244
+ if not @main.nil?
245
+ @create_manifest = true
246
+ path = File.join(@path, @main)
247
+ if not File.exist? path
248
+ raise Error, "Main script isn't exist in #{path}."
249
+ end
250
+ end
251
+ if @main.nil? and not File.directory? @path
252
+ @main = File.basename(@path)
253
+ end
254
+
255
+ if @include_jruby
256
+ if @jruby.nil?
257
+ if ENV['JRUBY_HOME'].nil?
258
+ raise Error, "Can't find JRuby, please set it manually."
259
+ else
260
+ @jruby = File.join(ENV['JRUBY_HOME'], "lib", "jruby.jar")
261
+ end
262
+ end
263
+ if not File.exist? @jruby
264
+ raise Error, "JRuby isn't exist in #{@jruby}."
265
+ end
266
+ end
267
+
268
+ number = Time.now.to_i
269
+ begin
270
+ number += 1
271
+ @build_dir = File.join(Dir.tmpdir, "ruby2jar#{number}")
272
+ end while File.exist? @build_dir
273
+ @app_dir = File.join(@build_dir, "ruby", "app")
274
+ @gems_dir = File.join(@build_dir, "ruby", "gems")
275
+
276
+ @init_require_paths = @require_paths.map { |i| "ruby/app/#{i}"}
277
+
278
+ Dir.mkdir @build_dir
279
+ File.chmod 0700, @build_dir
280
+ Dir.mkdir File.join(@build_dir, "ruby")
281
+ Dir.mkdir @app_dir
282
+ Dir.mkdir @gems_dir
283
+
284
+ # Change current dir
285
+ @last_current_dir = Dir.pwd
286
+ Dir.chdir @build_dir
287
+ end
288
+
289
+ # Copy application, gems and JRuby
290
+ def copy
291
+ if File.directory? @path
292
+ @files.each do |src|
293
+ dest = File.join(@app_dir, src[@path.length..-1])
294
+ if File.directory? src
295
+ FileUtils.mkdir_p(dest)
296
+ else
297
+ FileUtils.mkdir_p(File.dirname(dest))
298
+ FileUtils.copy src, dest
299
+ end
300
+ end
301
+ else
302
+ FileUtils.copy @path, @app_dir
303
+ end
304
+
305
+ @loaded_gem_versions = []
306
+ @loaded_gems = []
307
+ @gems.each { |gem| copy_gem(gem[0], gem[1]) }
308
+
309
+ ([@app_dir] + Dir.glob(File.join(@gems_dir, "*"))).each do |dir|
310
+ ext = File.join(dir, "ext")
311
+ Dir.glob(File.join(ext, "**", "*.{java,class}")).each do |file|
312
+ if ".java" == File.extname(file)
313
+ if File.exist? file[0..-6] + ".class"
314
+ File.delete file
315
+ next
316
+ end
317
+ end
318
+ dest = File.join(@build_dir, file[ext.length..-1])
319
+ FileUtils.makedirs File.dirname(dest)
320
+ FileUtils.move file, dest
321
+ end
322
+ end
323
+ end
324
+
325
+ # Find gems and copy it and it's dependencies
326
+ def copy_gem(gem, version = nil)
327
+ specs = @gems_index.find_name(gem, version)
328
+ if specs.empty?
329
+ raise Error, "Can't find gem #{gem}"
330
+ end
331
+ spec = specs.first
332
+
333
+ if @loaded_gem_versions.include? spec.full_name
334
+ return
335
+ end
336
+ if @loaded_gems.include? gem
337
+ raise Error, "Gem #{spec.name} is already added with different version"
338
+ end
339
+
340
+ gem_dir = File.join(@gems_dir, gem)
341
+ FileUtils.cp_r File.join(spec.full_gem_path, "."), gem_dir
342
+
343
+ config = File.join(@gems_dir, gem, "java.yaml")
344
+ if File.exist? config
345
+ @configs[gem] = YAML::load_file(config)
346
+ File.delete config
347
+ jar = @configs[gem]['jar']
348
+ if not jar.nil? and not jar['exclude'].nil?
349
+ jar['exclude'].map { |i| File.join(gem_dir, i) }.each do |files|
350
+ FileUtils.rm Dir.glob(files)
351
+ end
352
+ end
353
+ end
354
+
355
+ @loaded_gem_versions << spec.full_name
356
+ @loaded_gems << gem
357
+ @init_require_paths += spec.require_paths.map{|i| "ruby/gems/#{gem}/#{i}"}
358
+
359
+ spec.dependencies.each { |i| copy_gem(i) }
360
+ end
361
+
362
+ # Create init script to set rubygems variables and start main script
363
+ def create_init
364
+ return if @main.nil?
365
+
366
+ File.open(File.join(@build_dir, "ruby", "init.rb"), "w") do |file|
367
+ file.puts "module Kernel"
368
+ file.puts " def gem(name, *version); end"
369
+ file.puts " alias ruby2jar_original_require require"
370
+ file.puts " def require(file)"
371
+ file.puts " ruby2jar_original_require(file)"
372
+ file.puts " rescue LoadError => error"
373
+ file.puts " raise error if not error.message.include? 'no such file to load'"
374
+ file.puts " $LOAD_PATH.each do |path|"
375
+ file.puts " begin"
376
+ file.puts " ruby2jar_original_require(File.join(path, file))"
377
+ file.puts " return"
378
+ file.puts " rescue LoadError => error"
379
+ file.puts " raise error if not error.message.include? 'no such file to load'"
380
+ file.puts " end"
381
+ file.puts " end"
382
+ file.puts " end"
383
+ file.puts "end"
384
+ @init_require_paths.each do |path|
385
+ file.puts '$LOAD_PATH << "' + path + '"'
386
+ end
387
+ file.puts 'require "ruby/app/' + @main.sub(/\.rb$/, '') + '"'
388
+ end
389
+ @manifest["Main-Class"] = "ruby.init" if not @manifest.include? "Main-Class"
390
+ end
391
+
392
+ # Compile Ruby and Java sources
393
+ def compile
394
+ `jrubyc -p "" ./`
395
+
396
+ Dir.glob(File.join(@build_dir, "**", "*.java")).each do |file|
397
+ `javac #{@javac_args} -sourcepath ./ "#{file}"`
398
+ end
399
+
400
+ Dir.glob(File.join(@build_dir, "**", "*.{rb,java}")).each do |file|
401
+ File.delete file
402
+ end
403
+ end
404
+
405
+ # Package files in one JAR
406
+ def package
407
+ if @include_jruby
408
+ `jar -xf "#{@jruby}"`
409
+ end
410
+
411
+ FileUtils.makedirs File.dirname(@jar)
412
+
413
+ if @create_manifest
414
+ @manifest_file = Tempfile.new("ruby2jar_manifest")
415
+ @manifest.each_pair do |name, value|
416
+ @manifest_file.puts "#{name}: #{value}"
417
+ end
418
+ @manifest_file.close(false)
419
+
420
+ `jar -cvfm "#{@jar}" "#{@manifest_file.path}" ./`
421
+ else
422
+ `jar -cf "#{@jar}" ./`
423
+ end
424
+ end
425
+
426
+ # Delete all temporal files
427
+ def finish
428
+ if not @last_current_dir.nil?
429
+ Dir.chdir @last_current_dir
430
+ end
431
+ if not @build_dir.nil?
432
+ FileUtils.rm_r @build_dir
433
+ end
434
+ end
435
+ end
436
+ end