warbler 1.2.1 → 1.3.0.beta1
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/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
|
}
|