ruby2jar 0.1

Sign up to get free protection for your applications and to get access to all the features.
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