warbler 1.2.1 → 1.3.0.beta1
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile +8 -5
- data/History.txt +5 -0
- data/Manifest.txt +43 -23
- data/README.txt +67 -26
- data/Rakefile +17 -6
- data/ext/JarMain.java +147 -0
- data/ext/{Main.java → WarMain.java} +4 -4
- data/ext/{WarblerWar.java → WarblerJar.java} +79 -13
- data/ext/{WarblerWarService.java → WarblerJarService.java} +2 -2
- data/lib/warbler/application.rb +9 -9
- data/lib/warbler/config.rb +58 -204
- data/lib/warbler/gems.rb +2 -2
- data/lib/warbler/jar.rb +247 -0
- data/lib/warbler/task.rb +28 -60
- data/lib/warbler/templates/config.erb +1 -1
- data/lib/warbler/templates/rack.erb +1 -1
- data/lib/warbler/templates/rails.erb +1 -1
- data/lib/warbler/traits/bundler.rb +58 -0
- data/lib/warbler/traits/gemspec.rb +64 -0
- data/lib/warbler/traits/jar.rb +53 -0
- data/lib/warbler/traits/merb.rb +34 -0
- data/lib/warbler/traits/nogemspec.rb +41 -0
- data/lib/warbler/traits/rack.rb +31 -0
- data/lib/warbler/traits/rails.rb +57 -0
- data/lib/warbler/traits/war.rb +191 -0
- data/lib/warbler/traits.rb +105 -0
- data/lib/warbler/version.rb +1 -1
- data/lib/warbler/war.rb +1 -247
- data/lib/warbler.rb +2 -5
- data/lib/warbler_jar.jar +0 -0
- data/spec/sample_jar/History.txt +6 -0
- data/spec/sample_jar/Manifest.txt +8 -0
- data/spec/sample_jar/README.txt +30 -0
- data/spec/sample_jar/lib/sample_jar.rb +6 -0
- data/spec/sample_jar/sample_jar.gemspec +41 -0
- data/spec/sample_jar/test/test_sample_jar.rb +8 -0
- data/spec/{sample → sample_war}/app/controllers/application.rb +0 -0
- data/spec/{sample → sample_war}/app/helpers/application_helper.rb +0 -0
- data/spec/{sample → sample_war}/config/boot.rb +0 -0
- data/spec/{sample → sample_war}/config/database.yml +0 -0
- data/spec/{sample → sample_war}/config/environment.rb +0 -0
- data/spec/{sample → sample_war}/config/environments/development.rb +0 -0
- data/spec/{sample → sample_war}/config/environments/production.rb +0 -0
- data/spec/{sample → sample_war}/config/environments/test.rb +0 -0
- data/spec/{sample → sample_war}/config/initializers/inflections.rb +0 -0
- data/spec/{sample → sample_war}/config/initializers/mime_types.rb +0 -0
- data/spec/{sample → sample_war}/config/initializers/new_rails_defaults.rb +0 -0
- data/spec/{sample → sample_war}/config/routes.rb +0 -0
- data/spec/{sample → sample_war}/lib/tasks/utils.rake +0 -0
- data/spec/{sample → sample_war}/public/404.html +0 -0
- data/spec/{sample → sample_war}/public/422.html +0 -0
- data/spec/{sample → sample_war}/public/500.html +0 -0
- data/spec/{sample → sample_war}/public/favicon.ico +0 -0
- data/spec/{sample → sample_war}/public/index.html +0 -0
- data/spec/{sample → sample_war}/public/robots.txt +0 -0
- data/spec/spec_helper.rb +40 -0
- data/spec/warbler/application_spec.rb +2 -9
- data/spec/warbler/config_spec.rb +101 -83
- data/spec/warbler/jar_spec.rb +763 -0
- data/spec/warbler/task_spec.rb +56 -41
- data/spec/warbler/traits_spec.rb +16 -0
- data/spec/warbler/war_spec.rb +2 -492
- data/warble.rb +36 -32
- metadata +57 -35
- data/lib/warbler_war.jar +0 -0
data/Gemfile
CHANGED
@@ -1,11 +1,14 @@
|
|
1
1
|
source "http://rubygems.org/"
|
2
2
|
|
3
3
|
gem "rake", ">= 0.8.7"
|
4
|
-
gem "rdoc"
|
5
4
|
gem "rubyzip"
|
6
5
|
gem "jruby-jars"
|
7
6
|
gem "jruby-rack"
|
8
|
-
|
9
|
-
|
10
|
-
gem "
|
11
|
-
gem "
|
7
|
+
|
8
|
+
group :development do
|
9
|
+
gem "rspec", "~> 1.3"
|
10
|
+
gem "diff-lcs"
|
11
|
+
gem "rcov", ">= 0.9.8"
|
12
|
+
gem "hoe", ">= 2.3.2"
|
13
|
+
gem "rdoc"
|
14
|
+
end
|
data/History.txt
CHANGED
data/Manifest.txt
CHANGED
@@ -5,46 +5,66 @@ Manifest.txt
|
|
5
5
|
README.txt
|
6
6
|
Rakefile
|
7
7
|
bin/warble
|
8
|
-
ext/
|
9
|
-
ext/
|
10
|
-
ext/
|
8
|
+
ext/JarMain.java
|
9
|
+
ext/WarMain.java
|
10
|
+
ext/WarblerJar.java
|
11
|
+
ext/WarblerJarService.java
|
11
12
|
lib/warbler
|
12
13
|
lib/warbler.rb
|
13
14
|
lib/warbler/application.rb
|
14
15
|
lib/warbler/config.rb
|
15
16
|
lib/warbler/gems.rb
|
17
|
+
lib/warbler/jar.rb
|
16
18
|
lib/warbler/task.rb
|
17
19
|
lib/warbler/templates
|
18
20
|
lib/warbler/templates/config.erb
|
19
21
|
lib/warbler/templates/rack.erb
|
20
22
|
lib/warbler/templates/rails.erb
|
23
|
+
lib/warbler/traits
|
24
|
+
lib/warbler/traits.rb
|
25
|
+
lib/warbler/traits/bundler.rb
|
26
|
+
lib/warbler/traits/gemspec.rb
|
27
|
+
lib/warbler/traits/jar.rb
|
28
|
+
lib/warbler/traits/merb.rb
|
29
|
+
lib/warbler/traits/nogemspec.rb
|
30
|
+
lib/warbler/traits/rack.rb
|
31
|
+
lib/warbler/traits/rails.rb
|
32
|
+
lib/warbler/traits/war.rb
|
21
33
|
lib/warbler/version.rb
|
22
34
|
lib/warbler/war.rb
|
23
|
-
lib/
|
24
|
-
spec/
|
25
|
-
spec/
|
26
|
-
spec/
|
27
|
-
spec/
|
28
|
-
spec/
|
29
|
-
spec/
|
30
|
-
spec/
|
31
|
-
spec/
|
32
|
-
spec/
|
33
|
-
spec/
|
34
|
-
spec/
|
35
|
-
spec/
|
36
|
-
spec/
|
37
|
-
spec/
|
38
|
-
spec/
|
39
|
-
spec/
|
40
|
-
spec/
|
41
|
-
spec/
|
42
|
-
spec/
|
35
|
+
lib/warbler_jar.jar
|
36
|
+
spec/sample_jar/History.txt
|
37
|
+
spec/sample_jar/Manifest.txt
|
38
|
+
spec/sample_jar/README.txt
|
39
|
+
spec/sample_jar/lib/sample_jar.rb
|
40
|
+
spec/sample_jar/sample_jar.gemspec
|
41
|
+
spec/sample_jar/test/test_sample_jar.rb
|
42
|
+
spec/sample_war/app/controllers/application.rb
|
43
|
+
spec/sample_war/app/helpers/application_helper.rb
|
44
|
+
spec/sample_war/config/boot.rb
|
45
|
+
spec/sample_war/config/database.yml
|
46
|
+
spec/sample_war/config/environment.rb
|
47
|
+
spec/sample_war/config/environments/development.rb
|
48
|
+
spec/sample_war/config/environments/production.rb
|
49
|
+
spec/sample_war/config/environments/test.rb
|
50
|
+
spec/sample_war/config/initializers/inflections.rb
|
51
|
+
spec/sample_war/config/initializers/mime_types.rb
|
52
|
+
spec/sample_war/config/initializers/new_rails_defaults.rb
|
53
|
+
spec/sample_war/config/routes.rb
|
54
|
+
spec/sample_war/lib/tasks/utils.rake
|
55
|
+
spec/sample_war/public/404.html
|
56
|
+
spec/sample_war/public/422.html
|
57
|
+
spec/sample_war/public/500.html
|
58
|
+
spec/sample_war/public/favicon.ico
|
59
|
+
spec/sample_war/public/index.html
|
60
|
+
spec/sample_war/public/robots.txt
|
43
61
|
spec/spec_helper.rb
|
44
62
|
spec/warbler/application_spec.rb
|
45
63
|
spec/warbler/config_spec.rb
|
46
64
|
spec/warbler/gems_spec.rb
|
65
|
+
spec/warbler/jar_spec.rb
|
47
66
|
spec/warbler/task_spec.rb
|
67
|
+
spec/warbler/traits_spec.rb
|
48
68
|
spec/warbler/war_spec.rb
|
49
69
|
warble.rb
|
50
70
|
web.xml.erb
|
data/README.txt
CHANGED
@@ -1,18 +1,20 @@
|
|
1
1
|
= Warbler
|
2
2
|
|
3
|
-
Warbler is a gem to make a
|
4
|
-
|
5
|
-
bundle up all of your application files for
|
6
|
-
|
3
|
+
Warbler is a gem to make a Java jar or war file out of any Ruby,
|
4
|
+
Rails, Merb, or Rack application. Warbler provides a minimal,
|
5
|
+
flexible, Ruby-like way to bundle up all of your application files for
|
6
|
+
deployment to a Java environment.
|
7
7
|
|
8
8
|
Warbler provides a sane set of out-of-the box defaults that should allow most
|
9
|
-
Ruby
|
9
|
+
Ruby applications to assemble and Just Work.
|
10
10
|
|
11
11
|
== Getting Started
|
12
12
|
|
13
13
|
1. Install the gem: <tt>gem install warbler</tt>.
|
14
|
-
2. Run warbler in the top directory of your
|
15
|
-
|
14
|
+
2. Run warbler in the top directory of your application: <tt>warble</tt>.
|
15
|
+
3a. For a web project, deploy your myapp.war file to your favorite Java
|
16
|
+
application server.
|
17
|
+
3b. For a standalone applications, just run it: <tt>java -jar myapp.jar</tt>.
|
16
18
|
|
17
19
|
== Usage
|
18
20
|
|
@@ -21,23 +23,23 @@ defined tasks.
|
|
21
23
|
|
22
24
|
$ warble -T
|
23
25
|
warble compiled # Feature: precompile all Ruby files
|
24
|
-
warble config # Generate a configuration file to customize your
|
26
|
+
warble config # Generate a configuration file to customize your archive
|
25
27
|
warble executable # Feature: make an executable archive
|
26
|
-
warble gemjar # Feature: package gem repository inside a
|
28
|
+
warble gemjar # Feature: package gem repository inside a war
|
27
29
|
warble pluginize # Install Warbler tasks in your Rails application
|
28
30
|
warble version # Display version of Warbler
|
29
|
-
warble war # Create the project
|
30
|
-
warble war:clean # Remove the
|
31
|
+
warble war # Create the project war file
|
32
|
+
warble war:clean # Remove the project war file
|
31
33
|
warble war:debug # Dump diagnostic information
|
32
34
|
|
33
|
-
Type <tt>warble</tt>
|
35
|
+
Type <tt>warble</tt> to create the jar or war file.
|
34
36
|
|
35
37
|
== Features
|
36
38
|
|
37
39
|
Warbler "features" are small Rake tasks that run before the creation
|
38
|
-
of the war file and make manipulations to the
|
40
|
+
of the war file and make manipulations to the archive structure. For
|
39
41
|
instance, the +executable+ feature makes your war file capable of
|
40
|
-
running on its own
|
42
|
+
running on its own, without a servlet container:
|
41
43
|
|
42
44
|
warble executable war
|
43
45
|
|
@@ -54,9 +56,11 @@ Currently, three features are available.
|
|
54
56
|
* +gemjar+: This bundles all gems into a single gem file to reduce the
|
55
57
|
number of files in the .war. This is mostly useful for Google
|
56
58
|
AppEngine where the number of files per application has a limit.
|
59
|
+
(Note: not applicable for jar-based applications.)
|
57
60
|
* +executable+: This bundles an embedded web server into the .war so
|
58
61
|
that it can either be deployed into a traditional java web server or
|
59
62
|
run as a standalone application using <tt>java -jar myapp.war</tt>.
|
63
|
+
(Note: jar-based applications are executable by default.)
|
60
64
|
* +compiled+: This uses +jrubyc+ to precompile all .rb files in your
|
61
65
|
application to .class files and includes those in the .war instead
|
62
66
|
of the Ruby sources.
|
@@ -64,15 +68,50 @@ Currently, three features are available.
|
|
64
68
|
Features may form the basis for a third-party plugin system in the
|
65
69
|
future if there is demand.
|
66
70
|
|
67
|
-
==
|
71
|
+
== War or Jar?
|
72
|
+
|
73
|
+
War-based projects are for Rails, Merb, or Rack-based web
|
74
|
+
applications. They usually contain a <tt>config/environment.rb</tt>
|
75
|
+
file, a <tt>config/init.rb</tt> file, or a <tt>config.ru</tt> file.
|
76
|
+
The presence of these files are used to determine if the project
|
77
|
+
is a web application, and thus a Java EE compatible war file is built
|
78
|
+
for the project.
|
79
|
+
|
80
|
+
Jar-based projects are for standalone Ruby applications. Usually a
|
81
|
+
Ruby application has a launcher script in the <tt>bin</tt> directory
|
82
|
+
and Ruby code in the <tt>lib</tt> directory. Warbler packages the
|
83
|
+
application so that <tt>java -jar myapp.jar</tt> runs the launcher
|
84
|
+
script.
|
85
|
+
|
86
|
+
== Jar Files
|
87
|
+
|
88
|
+
=== Gem Specification (gemspec) Files
|
89
|
+
|
90
|
+
If your project has a <tt>.gemspec</tt> file in the top directory, it
|
91
|
+
will be used to configure the project's dependencies, launcher script,
|
92
|
+
require paths, and the files to be included in the archive. For best
|
93
|
+
results make sure your gemspec specifies all of the following
|
94
|
+
attributes:
|
95
|
+
|
96
|
+
* +default_executable+
|
97
|
+
* +files+
|
98
|
+
* +require_paths+
|
99
|
+
* runtime dependencies added with +add_dependency+
|
100
|
+
|
101
|
+
If your project do not have a <tt>.gemspec</tt>, Warbler will attempt
|
102
|
+
to guess the launcher from the contents of the <tt>bin</tt> directory
|
103
|
+
and use the <tt>lib</tt> directory as the lone require path. All files
|
104
|
+
in the project will be included in the archive.
|
68
105
|
|
69
106
|
=== Bundler
|
70
107
|
|
71
108
|
Applications that use Bundler[http://gembundler.com/], detected via
|
72
|
-
presence of a +Gemfile+, will have the gems packaged up into the
|
73
|
-
|
74
|
-
and +:test+ will be excluded by default, unless you
|
75
|
-
+config.bundle_without+ in +config/warble.rb+.
|
109
|
+
presence of a +Gemfile+, will have the gems packaged up into the
|
110
|
+
archive along with the Gemfile. The Bundler groups named
|
111
|
+
+:development+ and +:test+ will be excluded by default, unless you
|
112
|
+
specify with +config.bundle_without+ in +config/warble.rb+.
|
113
|
+
|
114
|
+
== War Files
|
76
115
|
|
77
116
|
=== Rails applications
|
78
117
|
|
@@ -120,13 +159,7 @@ of how to configure Warbler to package Camping and Sinatra apps.
|
|
120
159
|
uses? Gem.loaded_specs is available, but the application needs to be
|
121
160
|
loaded first before its contents are reliable.
|
122
161
|
|
123
|
-
|
124
|
-
|
125
|
-
The default configuration puts application files (+app+, +config+, +lib+,
|
126
|
-
+log+, +vendor+, +tmp+) under the .war file's WEB-INF directory, and files in
|
127
|
-
+public+ in the root of the .war file. Any Java .jar files stored in lib will
|
128
|
-
automatically be placed in WEB-INF/lib for placement on the web app's
|
129
|
-
classpath.
|
162
|
+
== Custom configuration
|
130
163
|
|
131
164
|
If the default settings are not appropriate for your application, you can
|
132
165
|
customize Warbler's behavior. To customize files, libraries, and gems included
|
@@ -139,6 +172,14 @@ Finally, edit the config/warble.rb to your taste. The generated
|
|
139
172
|
config/warble.rb file is fully-documented with the available options
|
140
173
|
and default values.
|
141
174
|
|
175
|
+
=== War layout
|
176
|
+
|
177
|
+
The default configuration puts application files (+app+, +config+, +lib+,
|
178
|
+
+log+, +vendor+, +tmp+) under the .war file's WEB-INF directory, and files in
|
179
|
+
+public+ in the root of the .war file. Any Java .jar files stored in lib will
|
180
|
+
automatically be placed in WEB-INF/lib for placement on the web app's
|
181
|
+
classpath.
|
182
|
+
|
142
183
|
=== Web.xml
|
143
184
|
|
144
185
|
Java web applications are configured mainly through this file, and Warbler
|
data/Rakefile
CHANGED
@@ -16,7 +16,7 @@ require 'spec/rake/verify_rcov'
|
|
16
16
|
|
17
17
|
MANIFEST = FileList["History.txt", "Manifest.txt", "README.txt", "Gemfile",
|
18
18
|
"LICENSE.txt", "Rakefile", "*.erb", "*.rb", "bin/*",
|
19
|
-
"ext/**/*", "lib/**/*", "spec/**/*.rb", "spec/sample
|
19
|
+
"ext/**/*", "lib/**/*", "spec/**/*.rb", "spec/sample*/**/*.*"
|
20
20
|
].to_a.reject{|f| f=~%r{spec/sample/(MANIFEST|link|web.xml)}}.sort.uniq
|
21
21
|
|
22
22
|
begin
|
@@ -33,7 +33,7 @@ begin
|
|
33
33
|
p.changes = p.paragraphs_of('History.txt', 0..1).join("\n\n")
|
34
34
|
p.description = p.paragraphs_of('README.txt', 1...2).join("\n\n")
|
35
35
|
p.extra_deps += [['rake', '>= 0.8.7'], ['jruby-jars', '>= 1.4.0'], ['jruby-rack', '>= 1.0.0'], ['rubyzip', '>= 0.9.4']]
|
36
|
-
p.clean_globs +=
|
36
|
+
p.clean_globs += %w(MANIFEST web.xml init.rb).map{|f| "spec/sample*/#{f}*" }
|
37
37
|
end
|
38
38
|
hoe.spec.files = MANIFEST
|
39
39
|
hoe.spec.dependencies.delete_if { |dep| dep.name == "hoe" }
|
@@ -61,6 +61,8 @@ end
|
|
61
61
|
Spec::Rake::SpecTask.new("spec:rcov") do |t|
|
62
62
|
t.spec_opts ||= []
|
63
63
|
t.spec_opts << "--options" << "spec/spec.opts"
|
64
|
+
t.rcov_opts ||= []
|
65
|
+
t.rcov_opts << "-x" << "/gems/"
|
64
66
|
t.rcov = true
|
65
67
|
end
|
66
68
|
|
@@ -76,16 +78,25 @@ begin
|
|
76
78
|
task :compile => "pkg/classes" do |t|
|
77
79
|
ant.javac :srcdir => "ext", :destdir => t.prerequisites.first,
|
78
80
|
:source => "1.5", :target => "1.5", :debug => true,
|
79
|
-
:classpath => "${java.class.path}:${sun.boot.class.path}"
|
81
|
+
:classpath => "${java.class.path}:${sun.boot.class.path}",
|
82
|
+
:includeantRuntime => false
|
80
83
|
end
|
81
84
|
|
82
85
|
task :jar => :compile do
|
83
|
-
ant.jar :basedir => "pkg/classes", :destfile => "lib/
|
86
|
+
ant.jar :basedir => "pkg/classes", :destfile => "lib/warbler_jar.jar", :includes => "*.class"
|
84
87
|
end
|
85
88
|
rescue LoadError
|
86
89
|
task :jar do
|
87
|
-
puts "Run 'jar' with JRuby >= 1.5 to re-compile the java
|
90
|
+
puts "Run 'jar' with JRuby >= 1.5 to re-compile the java jar booster"
|
88
91
|
end
|
89
92
|
end
|
90
93
|
|
91
|
-
|
94
|
+
# Make sure jar gets compiled before the gem is built
|
95
|
+
task Rake::Task['gem'].prerequisites.first => :jar
|
96
|
+
|
97
|
+
task :warbler_jar => 'pkg' do
|
98
|
+
ruby "-rubygems", "-Ilib", "-S", "bin/warble"
|
99
|
+
mv "warbler.jar", "pkg/warbler-#{Warbler::VERSION}.jar"
|
100
|
+
end
|
101
|
+
|
102
|
+
task :package => :warbler_jar
|
data/ext/JarMain.java
ADDED
@@ -0,0 +1,147 @@
|
|
1
|
+
/**
|
2
|
+
* Copyright (c) 2010 Engine Yard, Inc.
|
3
|
+
* This source code is available under the MIT license.
|
4
|
+
* See the file LICENSE.txt for details.
|
5
|
+
*/
|
6
|
+
|
7
|
+
import java.io.File;
|
8
|
+
import java.io.FileOutputStream;
|
9
|
+
import java.io.InputStream;
|
10
|
+
import java.lang.reflect.Method;
|
11
|
+
import java.net.URL;
|
12
|
+
import java.net.URLClassLoader;
|
13
|
+
import java.util.ArrayList;
|
14
|
+
import java.util.Arrays;
|
15
|
+
import java.util.Enumeration;
|
16
|
+
import java.util.List;
|
17
|
+
import java.util.jar.JarEntry;
|
18
|
+
import java.util.jar.JarFile;
|
19
|
+
|
20
|
+
public class JarMain implements Runnable {
|
21
|
+
public static final String MAIN = "/" + JarMain.class.getName().replace('.', '/') + ".class";
|
22
|
+
|
23
|
+
private String[] args;
|
24
|
+
private String path, jarfile;
|
25
|
+
private boolean debug;
|
26
|
+
private File extractRoot;
|
27
|
+
|
28
|
+
public JarMain(String[] args) throws Exception {
|
29
|
+
this.args = args;
|
30
|
+
URL mainClass = getClass().getResource(MAIN);
|
31
|
+
this.path = mainClass.toURI().getSchemeSpecificPart();
|
32
|
+
this.jarfile = mainClass.getFile().replace("!" + MAIN, "").replace("file:", "");
|
33
|
+
this.debug = isDebug();
|
34
|
+
this.extractRoot = File.createTempFile("jruby", "extract");
|
35
|
+
this.extractRoot.delete();
|
36
|
+
this.extractRoot.mkdirs();
|
37
|
+
Runtime.getRuntime().addShutdownHook(new Thread(this));
|
38
|
+
}
|
39
|
+
|
40
|
+
private URL[] extractJRuby() throws Exception {
|
41
|
+
JarFile jf = new JarFile(this.jarfile);
|
42
|
+
List<String> jarNames = new ArrayList<String>();
|
43
|
+
for (Enumeration<JarEntry> eje = jf.entries(); eje.hasMoreElements(); ) {
|
44
|
+
String name = eje.nextElement().getName();
|
45
|
+
if (name.startsWith("META-INF/lib") && name.endsWith(".jar")) {
|
46
|
+
jarNames.add("/" + name);
|
47
|
+
}
|
48
|
+
}
|
49
|
+
|
50
|
+
List<URL> urls = new ArrayList<URL>();
|
51
|
+
for (String name : jarNames) {
|
52
|
+
urls.add(extractJar(name));
|
53
|
+
}
|
54
|
+
|
55
|
+
return (URL[]) urls.toArray(new URL[urls.size()]);
|
56
|
+
}
|
57
|
+
|
58
|
+
private URL extractJar(String jarpath) throws Exception {
|
59
|
+
InputStream jarStream = new URL("jar:" + path.replace(MAIN, jarpath)).openStream();
|
60
|
+
String jarname = jarpath.substring(jarpath.lastIndexOf("/") + 1, jarpath.lastIndexOf("."));
|
61
|
+
File jarFile = new File(extractRoot, jarname + ".jar");
|
62
|
+
jarFile.deleteOnExit();
|
63
|
+
FileOutputStream outStream = new FileOutputStream(jarFile);
|
64
|
+
try {
|
65
|
+
byte[] buf = new byte[65536];
|
66
|
+
int bytesRead = 0;
|
67
|
+
while ((bytesRead = jarStream.read(buf)) != -1) {
|
68
|
+
outStream.write(buf, 0, bytesRead);
|
69
|
+
}
|
70
|
+
} finally {
|
71
|
+
jarStream.close();
|
72
|
+
outStream.close();
|
73
|
+
}
|
74
|
+
debug(jarname + ".jar extracted to " + jarFile.getPath());
|
75
|
+
return jarFile.toURI().toURL();
|
76
|
+
}
|
77
|
+
|
78
|
+
private int launchJRuby(URL[] jars) throws Exception {
|
79
|
+
System.setProperty("org.jruby.embed.class.path", "");
|
80
|
+
URLClassLoader loader = new URLClassLoader(jars);
|
81
|
+
Class scriptingContainerClass = Class.forName("org.jruby.embed.ScriptingContainer", true, loader);
|
82
|
+
Object scriptingContainer = scriptingContainerClass.newInstance();
|
83
|
+
|
84
|
+
Method argv = scriptingContainerClass.getDeclaredMethod("setArgv", new Class[] {String[].class});
|
85
|
+
argv.invoke(scriptingContainer, new Object[] {args});
|
86
|
+
Method setClassLoader = scriptingContainerClass.getDeclaredMethod("setClassLoader", new Class[] {ClassLoader.class});
|
87
|
+
setClassLoader.invoke(scriptingContainer, new Object[] {loader});
|
88
|
+
debug("invoking " + jarfile + " with: " + Arrays.deepToString(args));
|
89
|
+
|
90
|
+
Method runScriptlet = scriptingContainerClass.getDeclaredMethod("runScriptlet", new Class[] {String.class});
|
91
|
+
return ((Number) runScriptlet.invoke(scriptingContainer, new Object[] {
|
92
|
+
"begin\n" +
|
93
|
+
"require 'META-INF/init.rb'\n" +
|
94
|
+
"require 'META-INF/main.rb'\n" +
|
95
|
+
"0\n" +
|
96
|
+
"rescue SystemExit => e\n" +
|
97
|
+
"e.status\n" +
|
98
|
+
"end"
|
99
|
+
})).intValue();
|
100
|
+
}
|
101
|
+
|
102
|
+
private int start() throws Exception {
|
103
|
+
URL[] u = extractJRuby();
|
104
|
+
return launchJRuby(u);
|
105
|
+
}
|
106
|
+
|
107
|
+
private void debug(String msg) {
|
108
|
+
if (debug) {
|
109
|
+
System.out.println(msg);
|
110
|
+
}
|
111
|
+
}
|
112
|
+
|
113
|
+
private void delete(File f) {
|
114
|
+
if (f.isDirectory()) {
|
115
|
+
File[] children = f.listFiles();
|
116
|
+
for (int i = 0; i < children.length; i++) {
|
117
|
+
delete(children[i]);
|
118
|
+
}
|
119
|
+
}
|
120
|
+
f.delete();
|
121
|
+
}
|
122
|
+
|
123
|
+
public void run() {
|
124
|
+
delete(extractRoot);
|
125
|
+
}
|
126
|
+
|
127
|
+
public static void main(String[] args) {
|
128
|
+
try {
|
129
|
+
int exit = new JarMain(args).start();
|
130
|
+
System.exit(exit);
|
131
|
+
} catch (Exception e) {
|
132
|
+
Throwable t = e;
|
133
|
+
while (t.getCause() != null && t.getCause() != t) {
|
134
|
+
t = t.getCause();
|
135
|
+
}
|
136
|
+
|
137
|
+
if (isDebug()) {
|
138
|
+
t.printStackTrace();
|
139
|
+
}
|
140
|
+
System.exit(1);
|
141
|
+
}
|
142
|
+
}
|
143
|
+
|
144
|
+
private static boolean isDebug() {
|
145
|
+
return System.getProperty("warbler.debug") != null;
|
146
|
+
}
|
147
|
+
}
|
@@ -13,8 +13,8 @@ import java.io.File;
|
|
13
13
|
import java.io.FileOutputStream;
|
14
14
|
import java.util.Arrays;
|
15
15
|
|
16
|
-
public class
|
17
|
-
public static final String MAIN = "/" +
|
16
|
+
public class WarMain implements Runnable {
|
17
|
+
public static final String MAIN = "/" + WarMain.class.getName().replace('.', '/') + ".class";
|
18
18
|
public static final String WINSTONE_JAR = "/WEB-INF/winstone.jar";
|
19
19
|
|
20
20
|
private String[] args;
|
@@ -22,7 +22,7 @@ public class Main implements Runnable {
|
|
22
22
|
private boolean debug;
|
23
23
|
private File webroot;
|
24
24
|
|
25
|
-
public
|
25
|
+
public WarMain(String[] args) throws Exception {
|
26
26
|
this.args = args;
|
27
27
|
URL mainClass = getClass().getResource(MAIN);
|
28
28
|
this.path = mainClass.toURI().getSchemeSpecificPart();
|
@@ -94,7 +94,7 @@ public class Main implements Runnable {
|
|
94
94
|
|
95
95
|
public static void main(String[] args) {
|
96
96
|
try {
|
97
|
-
new
|
97
|
+
new WarMain(args).start();
|
98
98
|
} catch (Exception e) {
|
99
99
|
System.err.println("error: " + e.toString());
|
100
100
|
if (isDebug()) {
|
@@ -7,9 +7,14 @@
|
|
7
7
|
import java.io.Closeable;
|
8
8
|
import java.io.File;
|
9
9
|
import java.io.FileInputStream;
|
10
|
+
import java.io.FileNotFoundException;
|
10
11
|
import java.io.FileOutputStream;
|
11
12
|
import java.io.IOException;
|
13
|
+
import java.io.InputStream;
|
14
|
+
import java.util.regex.Matcher;
|
15
|
+
import java.util.regex.Pattern;
|
12
16
|
import java.util.zip.ZipEntry;
|
17
|
+
import java.util.zip.ZipInputStream;
|
13
18
|
import java.util.zip.ZipOutputStream;
|
14
19
|
|
15
20
|
import org.jruby.Ruby;
|
@@ -21,16 +26,17 @@ import org.jruby.anno.JRubyMethod;
|
|
21
26
|
import org.jruby.runtime.Block;
|
22
27
|
import org.jruby.runtime.ThreadContext;
|
23
28
|
import org.jruby.runtime.builtin.IRubyObject;
|
29
|
+
import org.jruby.util.ByteList;
|
24
30
|
import org.jruby.util.JRubyFile;
|
25
31
|
|
26
|
-
public class
|
32
|
+
public class WarblerJar {
|
27
33
|
public static void create(Ruby runtime) {
|
28
|
-
RubyModule task = runtime.getClassFromPath("Warbler::
|
29
|
-
task.defineAnnotatedMethods(
|
34
|
+
RubyModule task = runtime.getClassFromPath("Warbler::Jar");
|
35
|
+
task.defineAnnotatedMethods(WarblerJar.class);
|
30
36
|
}
|
31
37
|
|
32
38
|
@JRubyMethod
|
33
|
-
public static IRubyObject
|
39
|
+
public static IRubyObject create_jar(ThreadContext context, IRubyObject recv, IRubyObject jar_path, IRubyObject entries) {
|
34
40
|
final Ruby runtime = recv.getRuntime();
|
35
41
|
|
36
42
|
if (!(entries instanceof RubyHash)) {
|
@@ -39,7 +45,7 @@ public class WarblerWar {
|
|
39
45
|
|
40
46
|
RubyHash hash = (RubyHash) entries;
|
41
47
|
try {
|
42
|
-
FileOutputStream file = newFile(
|
48
|
+
FileOutputStream file = newFile(jar_path);
|
43
49
|
try {
|
44
50
|
ZipOutputStream zip = new ZipOutputStream(file);
|
45
51
|
addEntries(context, zip, hash);
|
@@ -57,6 +63,32 @@ public class WarblerWar {
|
|
57
63
|
return runtime.getNil();
|
58
64
|
}
|
59
65
|
|
66
|
+
@JRubyMethod
|
67
|
+
public static IRubyObject entry_in_jar(ThreadContext context, IRubyObject recv, IRubyObject jar_path, IRubyObject entry) {
|
68
|
+
final Ruby runtime = recv.getRuntime();
|
69
|
+
try {
|
70
|
+
InputStream entryStream = getStream(jar_path.convertToString().getUnicodeValue(),
|
71
|
+
entry.convertToString().getUnicodeValue());
|
72
|
+
try {
|
73
|
+
byte[] buf = new byte[16384];
|
74
|
+
ByteList blist = new ByteList();
|
75
|
+
int bytesRead = -1;
|
76
|
+
while ((bytesRead = entryStream.read(buf)) != -1) {
|
77
|
+
blist.append(buf, 0, bytesRead);
|
78
|
+
}
|
79
|
+
IRubyObject stringio = runtime.getModule("StringIO");
|
80
|
+
return stringio.callMethod(context, "new", runtime.newString(blist));
|
81
|
+
} finally {
|
82
|
+
close(entryStream);
|
83
|
+
}
|
84
|
+
} catch (IOException e) {
|
85
|
+
if (runtime.isDebug()) {
|
86
|
+
e.printStackTrace();
|
87
|
+
}
|
88
|
+
throw runtime.newIOErrorFromException(e);
|
89
|
+
}
|
90
|
+
}
|
91
|
+
|
60
92
|
private static void addEntries(ThreadContext context, ZipOutputStream zip, RubyHash entries) throws IOException {
|
61
93
|
RubyArray keys = entries.keys().sort(context, Block.NULL_BLOCK);
|
62
94
|
for (int i = 0; i < keys.getLength(); i++) {
|
@@ -77,7 +109,12 @@ public class WarblerWar {
|
|
77
109
|
if (value.isNil() || (f = getFile(value)).isDirectory()) {
|
78
110
|
zip.putNextEntry(new ZipEntry(entryName + "/"));
|
79
111
|
} else {
|
80
|
-
|
112
|
+
String path = f.getPath();
|
113
|
+
if (!f.exists()) {
|
114
|
+
path = value.convertToString().getUnicodeValue();
|
115
|
+
}
|
116
|
+
|
117
|
+
InputStream inFile = getStream(path, null);
|
81
118
|
try {
|
82
119
|
zip.putNextEntry(new ZipEntry(entryName));
|
83
120
|
byte[] buf = new byte[16384];
|
@@ -92,12 +129,8 @@ public class WarblerWar {
|
|
92
129
|
}
|
93
130
|
}
|
94
131
|
|
95
|
-
private static FileOutputStream newFile(IRubyObject
|
96
|
-
return new FileOutputStream(getFile(
|
97
|
-
}
|
98
|
-
|
99
|
-
private static FileInputStream openFile(File file) throws IOException {
|
100
|
-
return new FileInputStream(file);
|
132
|
+
private static FileOutputStream newFile(IRubyObject jar_path) throws IOException {
|
133
|
+
return new FileOutputStream(getFile(jar_path));
|
101
134
|
}
|
102
135
|
|
103
136
|
private static File getFile(IRubyObject path) {
|
@@ -108,8 +141,41 @@ public class WarblerWar {
|
|
108
141
|
private static void close(Closeable c) {
|
109
142
|
try {
|
110
143
|
c.close();
|
111
|
-
} catch (
|
144
|
+
} catch (Exception e) {
|
145
|
+
}
|
146
|
+
}
|
147
|
+
|
148
|
+
private static Pattern PROTOCOL = Pattern.compile("^[a-z][a-z0-9]+:");
|
149
|
+
|
150
|
+
private static InputStream getStream(String jar, String entry) throws IOException {
|
151
|
+
Matcher m = PROTOCOL.matcher(jar);
|
152
|
+
while (m.find()) {
|
153
|
+
jar = jar.substring(m.end());
|
154
|
+
m = PROTOCOL.matcher(jar);
|
112
155
|
}
|
156
|
+
|
157
|
+
String[] path = jar.split("!/");
|
158
|
+
InputStream stream = new FileInputStream(path[0]);
|
159
|
+
for (int i = 1; i < path.length; i++) {
|
160
|
+
stream = entryInJar(stream, path[i]);
|
161
|
+
}
|
162
|
+
|
163
|
+
if (entry == null) {
|
164
|
+
return stream;
|
165
|
+
}
|
166
|
+
|
167
|
+
return entryInJar(stream, entry);
|
113
168
|
}
|
114
169
|
|
170
|
+
private static InputStream entryInJar(InputStream jar, String entry) throws IOException {
|
171
|
+
ZipInputStream jstream = new ZipInputStream(jar);
|
172
|
+
ZipEntry zentry = null;
|
173
|
+
while ((zentry = jstream.getNextEntry()) != null) {
|
174
|
+
if (zentry.getName().equals(entry)) {
|
175
|
+
return jstream;
|
176
|
+
}
|
177
|
+
jstream.closeEntry();
|
178
|
+
}
|
179
|
+
throw new FileNotFoundException("entry '" + entry + "' not found in " + jar);
|
180
|
+
}
|
115
181
|
}
|
@@ -8,9 +8,9 @@ import java.io.IOException;
|
|
8
8
|
import org.jruby.Ruby;
|
9
9
|
import org.jruby.runtime.load.BasicLibraryService;
|
10
10
|
|
11
|
-
public class
|
11
|
+
public class WarblerJarService implements BasicLibraryService {
|
12
12
|
public boolean basicLoad(final Ruby runtime) throws IOException {
|
13
|
-
|
13
|
+
WarblerJar.create(runtime);
|
14
14
|
return true;
|
15
15
|
}
|
16
16
|
}
|